Silverlight+WCF 新手实例 象棋 主界面-在线用户区(二十四)

简介:

在线演示地址:Silverlight+WCF 新手实例 象棋 在线演示

演示已更新到此节介绍:Silverlight+WCF 新手实例 象棋 介绍III(二十三)

 

这节我们来实现在线用户区的显示,把上两节介绍那张图再弄来,看在线用户区是哪块:

 

一眼扫过看到了,是第四区,现在开始了,还是上次下棋区域一样的逻辑,往Index.xaml里拉一个Board控件,然后后台写两行代码代码一下。

当然了,得新建一个用户控件:就叫:OnlineUser.xaml,好,空白的在线用户建完了,下面还是两步实现加载:

1:界面拖一个Board到Index.xaml,现在界面上就有两行Board了:

第二个onlineUserBoard就是新添加进去的了。宽和高设置为230*260了。

复制代码
ExpandedBlockStart.gif
< Grid x:Name = " LayoutRoot "  Background = " White " >
        
< Border BorderBrush = " Silver "  BorderThickness = " 1 "  Height = " 544 "  HorizontalAlignment = " Left "  Margin = " 10,10,0,0 "  Name = " chessBoard "  VerticalAlignment = " Top "  Width = " 522 " ></ Border >
        
< Border BorderBrush = " Silver "  BorderThickness = " 1 "  Height = " 260 "  HorizontalAlignment = " Left "  Margin = " 756,10,0,0 "  Name = " onlineUserBoard "  VerticalAlignment = " Top "  Width = " 230 " ></ Border >
    
</ Grid >
复制代码

 

2:后台动态加载控件了,后台代码就两行,看今天新加的那。

复制代码
ExpandedBlockStart.gif
public  Index()
        {
            InitializeComponent();
            Chess chessControl
= new  Chess(); // 实例化控件
            chessBoard.Child  =  chessControl; // 加载控件
            OnlineUser onlineUserControl  =   new  OnlineUser(); // 今天新加的在线用户
            onlineUserBoard.Child  =  onlineUserControl;
        }
复制代码

 

OK,控件就相当于加载完了。接下来的任务就是要实现OnlineUser控件里的内容显示了:

 

接下来我们回到OnlineUser.xaml里,改一下总体宽和高为230*260:

复制代码
< UserControl ..省略一堆.. d:DesignHeight = " 260 "  d:DesignWidth = " 230 " >
    
    
< Grid x:Name = " LayoutRoot "  Background = " White " >

    
</ Grid >
</ UserControl >
复制代码

 

然后呢,往里放四个TextBlock和一个ListBox

复制代码
ExpandedBlockStart.gif
< Grid x:Name = " LayoutRoot "  Background = " White " >
        
< TextBlock Height = " 23 "  HorizontalAlignment = " Left "  Margin = " 9,10,0,0 "  Name = " textBlock1 "  Text = " 我的昵称: "  VerticalAlignment = " Top "   />
        
< TextBlock Height = " 23 "  HorizontalAlignment = " Left "  Margin = " 71,10,0,0 "  Name = " txtNickName "  Text = " txtNickName "  VerticalAlignment = " Top "  Width = " 164 "   />
        
< TextBlock Height = " 23 "  HorizontalAlignment = " Left "  Margin = " 9,39,0,0 "  Name = " textBlock3 "  Text = " 在线人数: "  VerticalAlignment = " Top "   />
        
< TextBlock Height = " 23 "  HorizontalAlignment = " Left "  Margin = " 71,39,0,0 "  Name = " txtOnlineCount "  Text = " 1 "  VerticalAlignment = " Top "  Width = " 71 "   />
        
< ListBox Height = " 190 "  HorizontalAlignment = " Left "  Margin = " 8,61,0,0 "  Name = " lbUserList "  VerticalAlignment = " Top "  Width = " 215 "   />
    
</ Grid >
复制代码

 

看这个不太直观,还是来张图:

现在看到布局情况了吧,界面布局就差不多了,接下来我们要获取服务端的用户列表,同时接收服务端的更新通知。

 

于是,转入WCF服务端了,加两个东东,一个获取用户列表,一个回调通知用户更新。[和房间列表几乎一个样]

打开IService.cs,加入接口,我们只要房间内的用户列表就行了:

[OperationContract]
Dictionary
< Guid, Player >  GetPlayerList( int  roomID); // 获取用户列表

 

然后增加回调接口,有新用户进入时,要通知我们的:

打开ICallBack.cs接口,由于只有两行,就顺便复制出来了[回调不熟悉的,回去再看通讯基础[十四--十七]那几节]:

通知用户那,由于用户有进入和退出,所以增加参数传递。

复制代码
ExpandedBlockStart.gif
interface  ICallBack
    {
        [OperationContract(IsOneWay 
=   true )]
        
void  NotifyRoomUpdate(Room room);
        [OperationContract(IsOneWay 
=   true )]
        
void  NotifyUserUpdate(Player player,  bool  isEnter); // 通知用户
    }
复制代码

 

说了N次了,回调的是方法是给客户端实现的,所以我们在服务端不实现。

 

但我们那个GetPlayerList还是得实现的,我们回到Service.svc.cs,实现接口

看,代码相当的简洁简单吧,没办法,我们的存档结构Dictionary存的好。

复制代码
ExpandedBlockStart.gif
  #region  IService 成员

        
// 获取房间用户列表
         public  Dictionary < Guid, Player >  GetPlayerList( int  roomID)
        {
            
if  (playerList.ContainsKey(roomID))
            {
                
return  playerList[roomID];
            }
            
return   null ;
        }

        
#endregion
复制代码

 

用户列表获取完事了,但是用户通知更新还没完事呢,这里一并处理了:

 

在用户进入房间和退出房间的时候,我们要调用一下那个回调通知房间内用户更新:

我们回到Notify类,上节有了一个通知房间更新的方法,这里我们添加一个用户更新的方法:

还是一样的很简洁,用户不是自己,就通知更新。

复制代码
ExpandedBlockStart.gif
  internal   static   void  User(Dictionary < int , Dictionary < Guid, Player >>  playerList, Player player, bool  isEnter)
        {
            
// 这里是今天新加的,通知房间内用户更新用户
             foreach  (KeyValuePair < Guid, Player >  item  in  playerList[ 0 ])
            {
                
if  (item.Value.ID  !=  player.ID)
                {
                    item.Value.CallBack.NotifyUserUpdate(player,isEnter);
                }
            }
        }
复制代码

 

现在回到进入房间和退出房间的方法里,调用下这个方法吧:

方法太长,就不全复制,这里复制两行好了:

复制代码
ExpandedBlockStart.gif
public   bool  EnterRoom(Player player,  int  roomID)
        {
          
// ...省略一堆...

            
// 这里是以前用的,通知0房间的人[未进入房间的人]都更新此房间状态
            Notify.Room(playerList, room);
            
// 这里是今天新增加的,通知用户更新
            Notify.User(playerList, player,  true );
          
return   true ;
        }
复制代码

 

同样的,退出房间方法里也有,也复制两行代码好了:

复制代码
ExpandedBlockStart.gif
public   void  OutRoom(Player player,  int  roomID)
        {
            
if  (roomID  >   0 )
            {
               
// ...省略一堆...

              
// 这里是以前加的,通知0房间的人[未进入房间的人]都更新此房间状态
                Notify.Room(playerList, room);
             
// 这里是今天新增加的,通知用户退出房间更新
                Notify.User(playerList, player,  false );

            }
        }
复制代码

 

至此,WCF服务端代码就完成了,剩下的就是客户端获取显示了。

 

再次提醒,编绎WCF服务端项目,客户端更新引用引用

 

好了,我们回到OnlineUser.xaml.cs后台代码里,要开始获取数据了:

复制代码
ExpandedBlockStart.gif
public   partial   class  OnlineUser : UserControl
    {
        
public  OnlineUser()
        {
            InitializeComponent();
            App.client.GetPlayerListCompleted 
+=   new  EventHandler < GameService.GetPlayerListCompletedEventArgs > (client_GetPlayerListCompleted);
            App.client.GetPlayerListAsync(App.player.RoomID);
        }

        
void  client_GetPlayerListCompleted( object  sender, GameService.GetPlayerListCompletedEventArgs e)
        {
            
// 这里是获取用户列表显示区
        }
    }
复制代码

 

构造函数里我们调用了一下:GetPlayerListAsync,由于WCF都是异步的,所以都有一个事件来处理获取之后的执行方法:

在“e”的参数里,总是有我们要的数据:

接下来看看实现代码:

 

复制代码
ExpandedBlockStart.gif
void  client_GetPlayerListCompleted( object  sender, GameService.GetPlayerListCompletedEventArgs e)
        {
            
// 这里是获取用户列表显示区
            txtNickName.Text  =  App.player.NickName;
            
if  (e.Result  !=   null )
            {
                txtOnlineCount.Text 
=  e.Result.Count.ToString();
                lbUserList.Items.Clear();
                
foreach  (KeyValuePair < Guid, GameService.Player >  item  in  e.Result)
                {
                    lbUserList.Items.Add(item.Value.NickName 
+   " [ "   +  item.Value.ID.ToString().Substring( 1 4 +   " ] " );
                }
            }
        }
复制代码

 

1。先把自己的昵称打进去,

2。判断如果获取到数据,

3。显示下在线用户数,

4。然后清除下用户列表,

5。循环添加了,由于昵称可以重复,所以加个ID的前四位在后面用于区别一下。

在线用户列表就显示完了,接下来实现新用户进入和退出的更新:

构造函数里添加一行通知事件代码:

复制代码
ExpandedBlockStart.gif
public  OnlineUser()
        {
            
// ...这里省略刚才几行...
            App.client.NotifyUserUpdateReceived  +=   new  EventHandler < GameService.NotifyUserUpdateReceivedEventArgs > (client_NotifyUserUpdateReceived);
        }

        
void  client_NotifyUserUpdateReceived( object  sender, GameService.NotifyUserUpdateReceivedEventArgs e)
        {
            
// 这里是实现用户通知更新
        }
复制代码

 

接下来同样实现用户通知更新:

代码也很简洁了,如果是进入就添加,退出就删除,然后更新下在线用户数:

复制代码
ExpandedBlockStart.gif
    void  client_NotifyUserUpdateReceived( object  sender, GameService.NotifyUserUpdateReceivedEventArgs e)
        {
            
// 这里是实现用户通知更新
             if  (e.isEnter) // 进入
            {
                lbUserList.Items.Add(e.player.NickName 
+   " [ "   +  e.player.ID.ToString().Substring( 1 4 +   " ] " );
            }
            
else
            {
                lbUserList.Items.Remove(e.player.NickName 
+   " [ "   +  e.player.ID.ToString().Substring( 1 4 +   " ] " );

            }
            txtOnlineCount.Text 
=  lbUserList.Items.Count.ToString();
        }
复制代码

 

至此,我们就折腾完了,只是没有文字提示用户进入和退出,这个纠结了点。。。

就纠结了先吧,等下节我们实现在线聊天的时候,我们把文字往那边显示去。

OK,一切就绪,还是F5运行:

用了三个浏览器看了下效果,太阳,只有列表出来,没有被用户通知更新,查一下代码先

查出来了,原来在Notify类里的用户通知的房间号写错了,默认从房间通知那里Copy来的,房间号写了0。

修正一下代码:

复制代码
ExpandedBlockStart.gif
// 把playerList[0]改成playerList[player.RoomID]
  internal   static   void  User(Dictionary < int , Dictionary < Guid, Player >>  playerList, Player player, bool  isEnter)
        {
            
// 这里是新加的,通知0房间的人[未进入房间的人]都更新此房间状态
             foreach  (KeyValuePair < Guid, Player >  item  in  playerList[player.RoomID])
            {
                
if  (item.Value.ID  !=  player.ID)
                {
                    item.Value.CallBack.NotifyUserUpdate(player,isEnter);
                }
            }
        }
复制代码

 

 

OK,再次就绪,F5运行。

还是三个浏览器,这次正常了,OK,这节就到此结束了,下节再实现在线聊天,顺便把纠结的文字提示放那边去显示。

版权声明:本文原创发表于博客园,作者为路过秋天,原文链接:

http://www.cnblogs.com/cyq1162/archive/2010/07/24/1784222.html

相关文章
|
开发者 开发工具 定位技术
|
.NET 开发框架 数据安全/隐私保护
|
数据库 测试技术 安全
使用Entity Framework和WCF Ria Services开发SilverLight之2:POCO
在上一篇中《使用Entity Framework和WCF Ria Services开发SilverLight之1:简单模型》我们提出这类简单模型的几个问题: 1:实体模型被紧耦合在EDM中,同时它不能项目(模块)使用。
1207 0