• Silverlight+WCF 新手实例 象棋 主界面实时聊天区(二十五)


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

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

    本节连着Silverlight+WCF 新手实例 象棋 主界面-在线用户区(二十四) 发,主界面就不截图了,这节我们实现“实时聊天区”:

    这节内容几乎和上节一个样的逻辑

    1:新建一个用户控件:就叫:Chat.xaml,用来在线聊天

    2: 界面拖一个Border到Index.xaml,现在界面上有三个Border了,第三个chatBoard就是新添加进去的了。宽和高设置为230*280了。

    <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>
            
    <Border BorderBrush="Silver" BorderThickness="1" Height="280" HorizontalAlignment="Left" Margin="756,276,0,0" Name="chatBoard" VerticalAlignment="Top" Width="230" />
        
    </Grid>

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

    public Index()
            {
                InitializeComponent();
                Chess chessControl
    =new Chess();//实例化控件
                chessBoard.Child = chessControl;//加载控件
                OnlineUser onlineUserControl = new OnlineUser();//今天新加的在线用户
                onlineUserBoard.Child = onlineUserControl;
                Chat chatControl 
    = new Chat();//也是今天新加的---看这里看这里两行
                chatBoard.Child = chatControl;
            }

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

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

    <UserControl ...省略一堆...    d:DesignHeight="280" d:DesignWidth="230">
        
        
    <Grid x:Name="LayoutRoot" Background="White">

        
    </Grid>
    </UserControl>

    然后呢,往里放四个TextBlock和一个ListBox..-_-...不是啦,都照着上节复制了。。。

    然后呢,往里放一个TextBox;一个Button和一个ListBox,这个对了。。

    看清楚按钮哦,下面Button默认多了一个Click事件,不小心双击了下,反正早晚要双击的。

     <Grid x:Name="LayoutRoot" Background="White">
            
    <ListBox Height="226" HorizontalAlignment="Left" Name="lbMsg" VerticalAlignment="Top" Width="215" Margin="7,8,0,0" />
            
    <TextBox Height="29" HorizontalAlignment="Left"  Margin="7,238,0,0" Name="txtMsg" VerticalAlignment="Top" Width="143"  />
            
    <Button Content="提交" HorizontalAlignment="Left" Margin="159,240,0,13" Name="btnChat" Width="63" Click="btnChat_Click" />
        
    </Grid>

    好吧,还是和上次一样截张图吧:

    接着我们同样的,回WCF服务端写事件了[你点击提交,内容得提交到服务端吧,人家也提交,你这边得接收更新吧]。

    打开IService.cs,加入接口:

    [OperationContract(IsOneWay = true)]
    void Chat(Player player);

    看,我们把Player传递过去了,可是我们的聊天消息往哪放呢?Player可是没有属性来存这个消息的哦?没有?那就加呗。

    打开Player.cs,加一个附加信息属性[以后这属性大有用处]:

     /// <summary>
        
    /// 游戏玩家 by 路过秋天
        
    /// </summary>
        [DataContract]
        
    public class Player
        {
            
    //...省略几百个属性...

            
    /// <summary>
            
    /// 附加信息,杂七杂八的都可以
            
    /// </summary>
            [DataMember]
            
    public string AttachInfo
            {
                
    get;
                
    set;
            }
        }

    好了,现在有了,接着增加一个回调,通知大伙接收我发的消息:

    打开ICallBack.cs接口,增加:

     interface ICallBack
        {
           
    //..省略掉之前两个..两个也省,就是这么省
            [OperationContract(IsOneWay = true)]
            
    void NotifyChatUpdate(Player player);//通知聊天信息更新
        }

    接着实现接口的Chat方法,其实服务端接到消息,直接就转发了,所以代码,一行:

    public class Service : IService
        {
           
            
    //...省略几百行代码...

            
    public void Chat(Player player)
            {
                Notify.Chat(playerList, player);
            }

         }

    一来消息就把消息通知给大伙,可是那个Notify.Chat方法我们还没实现呢。

    切回到Notify类,我们来实现,相当的简单,遍历下房间用户,除了自己,每个人发一份:

    代码
     /// <summary>
        
    /// 通知 by 路过秋天
        
    /// </summary>
        public class Notify
        {
            
    //...省略掉之前的两个通知方法...
            internal static void Chat(Dictionary<int, Dictionary<Guid, Player>> playerList, Player player)
            {
                
    foreach (KeyValuePair<Guid, Player> item in playerList[player.RoomID])
                {
                    
    if (item.Value.ID != player.ID)
                    {
                        item.Value.CallBack.NotifyChatUpdate(player);
                    }
                }
                
            }
        }

    好了,服务写完了,回客户端调用了:

    记得编绎,更新服务引用。

    OK,现在回到Chat.xmal.cs代码里,我们要动手了:

    手痒,先写一个AddMsg(string msg)方法,用于添加消息

    public void AddMsg(string msg)
            {
                
    if (lbMsg.Items.Count > 50)
                {
                    
    for (int i = 0; i < 40; i++)
                    {
                        lbMsg.Items.RemoveAt(
    0);
                    }
                }
                lbMsg.Items.Add(
    string.Format("[{0}]{1}",DateTime.Now.ToLongTimeString(),msg));
                lbMsg.SelectedIndex 
    = lbMsg.Items.Count - 1;
                lbMsg.UpdateLayout();
                lbMsg.ScrollIntoView(lbMsg.SelectedItem);
            }

    说明:

    1。如果消息内容大于50条,我们就清除前面40条

    2。往ListBox里添加消息

    3。设置索引定位到最后一条

    4。更新下布局,为什么会有这个,详见:Silverlight4 ListBox bug

    5。滚动到最后一条去。

    OK,接着我们双击按钮,去Click事件里写代码:

    两行代码,就三行[刚加了一行判断..-_-.]!

    private void btnChat_Click(object sender, RoutedEventArgs e)
            {if (txtMsg.Text.Length > 0)
                {
                App.player.AttachInfo 
    = txtMsg.Text;//设置消息
                  App.client.ChatAsync(App.player);//传递消息
                }
            }

    可是WCF是异步的,咋不见那个发送后的回调函数呢?这里,我把它放构造函数里去了,总不能每点击就来一次事件,会造成不良影响的。

    看,来了,在回调里,我们添加一条消息,然后清空文本:

    public Chat()
            {
                InitializeComponent();
                App.client.ChatCompleted 
    += new EventHandler<System.ComponentModel.AsyncCompletedEventArgs>(client_ChatCompleted);
            }

            
    void client_ChatCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
            {
                AddMsg(
    "我 说:" + txtMsg.Text);
                txtMsg.Text 
    = "";
            }

    发送写完了,那接收呢?也是相当的相当的简单,就一行:

    public Chat()
            {
                
                
    //...省略掉刚才两行...

                App.client.NotifyChatUpdateReceived 
    += new EventHandler<GameService.NotifyChatUpdateReceivedEventArgs>(client_NotifyChatUpdateReceived);
            
            }
            
    void client_NotifyChatUpdateReceived(object sender, GameService.NotifyChatUpdateReceivedEventArgs e)
            {
                AddMsg(e.player.NickName 
    + " 说:" + e.player.AttachInfo);
            }

    一收到消息就直接AddMsg进去了,OK,到此小节就结束了。

    不过有时候我们喜欢用回车就发送消息,不想点按钮,那就为TextBox添加一个KeyDown事件吧

    上一张图,免的大伙不知在哪加:

    好,双击进去后事件代码,直接调用按钮事件:

     private void txtMsg_KeyDown(object sender, KeyEventArgs e)
            {
                
    if (e.Key == Key.Enter)
                {
                    
    if (txtMsg.Text.Length > 0)
                    {
                        btnChat_Click(
    nullnull);
                    }
                }
            }

    OK,至此,本节就真的结束了,现在F5运行,看看正常不正常:

    如上图,一切正常,打完收工!

    啊?上节那个纠结的进出房间的文本提示还没弄呢。。。-_-..下节写好了!

    版权声明:本文原创发表于 博客园,作者为 路过秋天 本文欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则视为侵权。
    个人微信公众号
    创业QQ群:617713515
    Donation(扫码支持作者):支付宝:
    Donation(扫码支持作者):微信:
  • 相关阅读:
    Odoo安装教程2-创建新的插件模块第一讲
    Odoo安装教程1-创建第一个 Odoo 应用
    Odoo开发教程21-Odoo服务器端开发者模式
    Ubuntu 安装LAMP
    Roundcube Webmail信息泄露漏洞(CVE-2015-5383)
    Roundcube Webmail跨站脚本漏洞(CVE-2015-5381 )
    Roundcube Webmail File Disclosure Vulnerability(CVE-2017-16651)
    Roundcube 1.2.2
    XAMPP重置MySQL密码
    python importlib动态导入模块
  • 原文地址:https://www.cnblogs.com/cyq1162/p/1784349.html
Copyright © 2020-2023  润新知