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


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

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

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

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

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

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

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

    <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:后台动态加载控件了,后台代码就两行,看今天新加的那。

    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

    <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接口,由于只有两行,就顺便复制出来了[回调不熟悉的,回去再看通讯基础[十四--十七]那几节]:

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

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

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

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

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

     #region IService 成员

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

            
    #endregion

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

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

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

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

     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);
                    }
                }
            }

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

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

    public bool EnterRoom(Player player, int roomID)
            {
              
    //...省略一堆...

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

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

    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后台代码里,要开始获取数据了:

    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”的参数里,总是有我们要的数据:

    接下来看看实现代码:

    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(14+ "]");
                    }
                }
            }

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

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

    3。显示下在线用户数,

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

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

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

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

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

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

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

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

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

                }
                txtOnlineCount.Text 
    = lbUserList.Items.Count.ToString();
            }

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

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

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

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

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

    修正一下代码:

    //把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,这节就到此结束了,下节再实现在线聊天,顺便把纠结的文字提示放那边去显示。

    版权声明:本文原创发表于 博客园,作者为 路过秋天 本文欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则视为侵权。
    个人微信公众号
    创业QQ群:617713515
    Donation(扫码支持作者):支付宝:
    Donation(扫码支持作者):微信:
  • 相关阅读:
    队列的python实现
    MySQL主从复制原理的是啥?
    Centos7 将应用添加快捷方式到applications 中以pycham为例[ubuntu]适用
    Centos7 虚拟环境安装Django 出现ImproperlyConfigured('SQLite 3.8.3 or later is required (found %s).' %Database.sqlite_version)错误
    Centos7 安装virtualenv bash: virtualenv: command not found...的解决
    Flask学习之 Jinja2模板引擎
    Flask学习之 Flask-Script 扩展
    Flask学习之 请求钩子
    VUE项目部署公网ip和端口以及使用域名访问配置
    Android app图标总是显示默认的机器人图标,且在manifest文件的application中修改无效...
  • 原文地址:https://www.cnblogs.com/cyq1162/p/1784222.html
Copyright © 2020-2023  润新知