这篇文章将讲述实现WPF的UI和WCF中的双工通信。实现文字部分的聊天功能和实现共享白板的功能。

画WPF的界面其实是一件麻烦的事情。虽然WPF和WindowsForm一样,能将控件拖到哪,它就在哪。我们在开发asp.net项目的时候用从原始的table布局,到现在流行的div+css布局。这些都需要设计人员的仔细设计。这个程序的布局我采用Grid和StackPanel两种方式。Gird类似html的表格布局,StackPanel就就像它的字面意思“堆栈面板”。

WPF的UI实现

首先新建一个wpf的应用程序,改名为ZqlChart。添加一个UserControl,用来实现登陆窗体,这个是用了StackPanel进行布局。XAML代码如下:

<UserControl x:Class="ZqlChart.LoginControl"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"Height="210" Width="350" Loaded="UserControl_Loaded"><StackPanel><Border Height="220" BorderBrush="#FFFFFFFF" BorderThickness="2,2,2,0" CornerRadius="5,5,0,0"><Border.Background><LinearGradientBrush EndPoint="0.713,0.698" StartPoint="0.713,-0.139"><GradientStop Color="#FFFFFFFF" Offset="0.933"/><GradientStop Color="LightBlue" Offset="0.337"/></LinearGradientBrush></Border.Background><StackPanel Name="infoPanel" Orientation="Vertical" Margin="10,10,10,10"><StackPanel Name="typePanel" Orientation="Horizontal"><RadioButton Name="chatTypeServer" FontSize="24" Margin="80,0,20,0" Checked="chatTypeServer_Checked" VerticalContentAlignment="Center">服务端</RadioButton><RadioButton Name="chatTypeClient" FontSize="24" Checked="chatTypeClient_Checked" VerticalContentAlignment="Center">客户端</RadioButton></StackPanel><StackPanel Name="serverPanel" Orientation="Horizontal" Margin="0,10,0,0"><Label Name="lblServer" FontSize="20" Width="120" HorizontalContentAlignment="Right" VerticalContentAlignment="Center">服务端:</Label><TextBox Height="30" Name="txtServer" Width="160" FontSize="20" VerticalContentAlignment="Center" /></StackPanel><StackPanel Name="usernamePanel" Orientation="Horizontal" Margin="0,10,0,10"><Label Name="lblUserName" FontSize="20" Width="120" HorizontalContentAlignment="Right">用户名:</Label><TextBox Height="30" Name="txtUserName" Width="160" FontSize="20" VerticalContentAlignment="Center" /></StackPanel><StackPanel Name="buttonPanel" Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center"><Button Name="btnLogin" Width="120" FontSize="20" Margin="10,10,10,10" Click="btnLogin_Click">连接</Button><Button Name="btnCancel" Width="120" FontSize="20" Margin="10,10,10,10" Click="btnCancel_Click">取消</Button></StackPanel></StackPanel></Border></StackPanel>
</UserControl>

界面效果如下:

聊天的主界面,如下图:

大框架是3行3列。XAML代码如下:

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"x:Name="ZqlChartMainWindow"x:Class="ZqlChart.ZqlChartWindow" Title="麒麟语音聊天室” Height="600" Width="800"Background="#FF3B3737" Loaded="Window_Loaded" MinWidth="800" MinHeight="500"><Grid x:Name="LayoutRoot" ><Grid.RowDefinitions><RowDefinition Height="50" /><RowDefinition Height="261" /><RowDefinition Height="250" /></Grid.RowDefinitions><Grid.ColumnDefinitions><ColumnDefinition Width="150" /><ColumnDefinition Width="580*" /><ColumnDefinition Width="48" /></Grid.ColumnDefinitions><Border Name="BorderUsersList" Grid.Column="0" Grid.Row="1" Grid.RowSpan="2" CornerRadius="8,8,8,8" Background="LightBlue" BorderThickness="0,0,4,4" ><ListView Name="lvUsers" Margin="10" FontSize="20"><ListView.BitmapEffect><DropShadowBitmapEffect /></ListView.BitmapEffect></ListView></Border><Border Name="BorderEditingType" Grid.ColumnSpan="3" CornerRadius="8,8,8,8" Background="LightBlue" BorderThickness="0,4,4,4"><StackPanel Orientation="Horizontal" VerticalAlignment="Center"><Button Margin="0,0,0,0"  Height="28" Width="121" Click="Button_Click" Background="White">与其语音聊天
                </Button><RadioButton Name="rbInk" Content="墨水" Margin="15,0,0,0" VerticalAlignment="Center" FontSize="20" IsChecked="True" Tag="{x:Static InkCanvasEditingMode.Ink}" Click="rbInkType_Checked"></RadioButton><RadioButton Name="rbEraserByStroke" Content="一笔一笔清除" Margin="15,0,0,0" VerticalAlignment="Center" FontSize="20" Tag="{x:Static InkCanvasEditingMode.EraseByStroke}" Click="rbInkType_Checked"></RadioButton><RadioButton Name="rbEraserByPoint" Content="一点一点清除" Margin="15,0,0,0" VerticalAlignment="Center" FontSize="20" Tag="{x:Static InkCanvasEditingMode.EraseByPoint}" Click="rbInkType_Checked"></RadioButton><TextBlock Margin="25,0,10,0" VerticalAlignment="Center" FontSize="20" >选择颜色:</TextBlock><Button Margin="0,0,0,0" Background="White" Height="28" Width="64" Click="OnSetFill"><Rectangle Width="54" Height="20" Stroke="Black" StrokeThickness="2"><Rectangle.Fill><SolidColorBrush Color="{Binding ElementName=ZqlChartMainWindow, Path=FillColor}" /></Rectangle.Fill></Rectangle></Button></StackPanel></Border><Border Name="BorderInkCanvas" Grid.Column="1" Grid.Row="1" Background="LightBlue" BorderThickness="4,4,4,4" CornerRadius="8,8,8,8" Grid.ColumnSpan="2"><InkCanvas x:Name="inkCanv" Margin="10" Background="White" StrokeCollected="inkCanv_StrokeCollected" StrokeErasing="inkCanv_StrokeErasing" StrokeErased="inkCanv_StrokeErased" VerticalAlignment="Top" ></InkCanvas></Border><Border Name="BorderInkMessage" Grid.Column="1" Grid.Row="2" Background="LightBlue" BorderThickness="0,0,4,4" CornerRadius="8,8,8,8" Grid.ColumnSpan="2"><Grid ><Grid.RowDefinitions><RowDefinition /><RowDefinition  Height="30" /></Grid.RowDefinitions><Grid.ColumnDefinitions><ColumnDefinition Width="500*" /><ColumnDefinition Width="62*" /><ColumnDefinition Width="62*" /></Grid.ColumnDefinitions><Border  Grid.Column="1" Grid.Row="1" Background="LightBlue" BorderThickness="4,4,4,4" CornerRadius="8,8,8,8" ><Button Content="发送"  Height="23"  Name="btnSend"  Click="btnSend_Click" /></Border><Border  Grid.ColumnSpan="3" Background="LightBlue" BorderThickness="4,4,4,4" CornerRadius="8,8,8,8" ><TextBox   Name="txtAllMessage" ><TextBox.BitmapEffect><DropShadowBitmapEffect /></TextBox.BitmapEffect></TextBox></Border><Border  Grid.Row="1" Background="LightBlue" BorderThickness="4,4,4,4" CornerRadius="8,8,8,8" ><TextBox Grid.Row="1" Name="txtMessage" /></Border><Border  Grid.Column="2" Grid.Row="1"  Background="LightBlue" BorderThickness="4,4,4,4" CornerRadius="8,8,8,8" ><Button  Content="关闭" Name="btnLeave"  Height="23" FontSize="10" Click="btnLeave_Click"></Button></Border></Grid></Border><Canvas Name="loginCanvas" Grid.Column="1" Grid.Row="1" Width="500" Height="300" VerticalAlignment="Top" HorizontalAlignment="Center" Margin="39,78,41,0" Grid.RowSpan="2" /></Grid>
</Window>窗体就设计好了。
WCF双工通信:

双工通信能允许服务通知用户当前的进度情况。我们可以通过使用指定CallbackContract的ServiceContract属性的服务使用双工,如服务器端的代码如下:

[ServiceContract(CallbackContract = typeof(IService1Callback))]
public interface IService1
{[OperationContract]string GetData(int value);
}[ServiceContract]
public interface IService1Callback
{[OperationContract]void Reply(string message);
}

客户端代码:

class Program
{static void Main(string[] args){var callback = new Service1Callback();var proxy = new Service1Client(new InstanceContext(callback));Console.WriteLine(proxy.GetData(42));Console.ReadLine();}
}class Service1Callback : IService1Callback
{public void Reply(string message){Console.WriteLine(message);}
}

这篇文章中我将利用WCF的双工通信实现文字聊天的功能和共享白板的功能。

定义协议:

    public interface IZqlChartService{[OperationContract()]bool Join(ChatUser chatUser);[OperationContract()]void Leave(ChatUser chatUser);[OperationContract]void SendBroadcastMessage(string strUserName, string message);[OperationContract()]bool IsUserNameTaken(string strUserName);[OperationContract()]void SendInkStrokes(MemoryStream memoryStream);}

定义回调:

    public interface IZqlChartServiceCallback{[OperationContract(IsOneWay = true)]void NotifyMessage(string message);[OperationContract(IsOneWay = true)]void UpdateUsersList(List<ChatUser> listChatUsers);[OperationContract(IsOneWay = true)]void OnInkStrokesUpdate(ChatUser chatUser, byte[] bytesStroke);[OperationContract(IsOneWay = true)]void ServerDisconnected();}

实现服务:

    public class ZqlChartService : IZqlChartService{public static Dictionary<IZqlChartServiceCallback, ChatUser> s_dictCallbackToUser = new Dictionary<IZqlChartServiceCallback, ChatUser>();public ZqlChartService(){}public bool Join(ChatUser chatUser){IZqlChartServiceCallback client = OperationContext.Current.GetCallbackChannel<IZqlChartServiceCallback>();if (s_dictCallbackToUser.ContainsValue(chatUser) == false){s_dictCallbackToUser.Add(client, chatUser);}foreach (IZqlChartServiceCallback callbackClient in s_dictCallbackToUser.Keys){callbackClient.UpdateUsersList(s_dictCallbackToUser.Values.ToList());}return true;}public void Leave(ChatUser chatUser){IZqlChartServiceCallback client = OperationContext.Current.GetCallbackChannel<IZqlChartServiceCallback>();if (s_dictCallbackToUser.ContainsKey(client)){s_dictCallbackToUser.Remove(client);}foreach (IZqlChartServiceCallback callbackClient in s_dictCallbackToUser.Keys){if (chatUser.IsServer){if (callbackClient != client){//server user logout, disconnect clientscallbackClient.ServerDisconnected();}}else{//normal user logoutcallbackClient.UpdateUsersList(s_dictCallbackToUser.Values.ToList());}}if (chatUser.IsServer){s_dictCallbackToUser.Clear();}}public bool IsUserNameTaken(string strNickName){foreach (ChatUser chatUser in s_dictCallbackToUser.Values){if (chatUser.NickName.ToUpper().CompareTo(strNickName) == 0){return true;}}return false;}public void SendInkStrokes(MemoryStream memoryStream){IZqlChartServiceCallback client = OperationContext.Current.GetCallbackChannel<IZqlChartServiceCallback>();foreach (IZqlChartServiceCallback callbackClient in s_dictCallbackToUser.Keys){if (callbackClient != OperationContext.Current.GetCallbackChannel<IZqlChartServiceCallback>()){callbackClient.OnInkStrokesUpdate(s_dictCallbackToUser[client], memoryStream.GetBuffer());}}}public void SendBroadcastMessage(string clientName, string message){IZqlChartServiceCallback client =OperationContext.Current.GetCallbackChannel<IZqlChartServiceCallback>();if (client != null){foreach (IZqlChartServiceCallback callbackClient in s_dictCallbackToUser.Keys){if (callbackClient != OperationContext.Current.GetCallbackChannel<IZqlChartServiceCallback>()){callbackClient.NotifyMessage(clientName + ": " + message);}}}}}

客户端:

    [System.Diagnostics.DebuggerStepThroughAttribute()][System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]public partial class ZqlChartServiceClient : System.ServiceModel.DuplexClientBase<IZqlChartService>, IZqlChartService{public ZqlChartServiceClient(System.ServiceModel.InstanceContext callbackInstance) :base(callbackInstance){}public ZqlChartServiceClient(System.ServiceModel.InstanceContext callbackInstance, string endpointConfigurationName) :base(callbackInstance, endpointConfigurationName){}public ZqlChartServiceClient(System.ServiceModel.InstanceContext callbackInstance, string endpointConfigurationName, string remoteAddress) :base(callbackInstance, endpointConfigurationName, remoteAddress){}public ZqlChartServiceClient(System.ServiceModel.InstanceContext callbackInstance, string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) :base(callbackInstance, endpointConfigurationName, remoteAddress){}public ZqlChartServiceClient(System.ServiceModel.InstanceContext callbackInstance, System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) :base(callbackInstance, binding, remoteAddress){}public bool Join(ZqlChartObjects.ChatUser chatUser){return base.Channel.Join(chatUser);}public void Leave(ZqlChartObjects.ChatUser chatUser){base.Channel.Leave(chatUser);}public bool IsUserNameTaken(string strUserName){return base.Channel.IsUserNameTaken(strUserName);}public void SendInkStrokes(System.IO.MemoryStream memoryStream){base.Channel.SendInkStrokes(memoryStream);}public void SendBroadcastMessage(string strUserName, string message){base.Channel.SendBroadcastMessage(strUserName, message);}}

客户端回调类:

    public class ClientCallBack : IZqlChartServiceCallback{public static ClientCallBack Instance;private SynchronizationContext m_uiSyncContext = null;private ZqlChartWindow m_mainWindow;//ActiveCallWindow _activeCallForm;//CallManager _callManager;public ClientCallBack(SynchronizationContext uiSyncContext, ZqlChartWindow mainWindow){m_uiSyncContext = uiSyncContext;m_mainWindow = mainWindow;}public void OnInkStrokesUpdate(ZqlChartObjects.ChatUser chatUser, byte[] bytesStroke){SendOrPostCallback callback =delegate(object state){m_mainWindow.OnInkStrokesUpdate(state as byte[] );};m_uiSyncContext.Post(callback, bytesStroke);SendOrPostCallback callback2 =delegate(object objchatUser){m_mainWindow.LastUserDraw(objchatUser as ZqlChartObjects.ChatUser);};m_uiSyncContext.Post(callback2, chatUser);}public void UpdateUsersList(List<ZqlChartObjects.ChatUser> listChatUsers){SendOrPostCallback callback =delegate(object objListChatUsers){m_mainWindow.UpdateUsersList(objListChatUsers as List<ZqlChartObjects.ChatUser>);};m_uiSyncContext.Post(callback, listChatUsers);}public void ServerDisconnected(){SendOrPostCallback callback =delegate(object dummy){m_mainWindow.ServerDisconnected();};m_uiSyncContext.Post(callback, null);}public void NotifyMessage(string message){SendOrPostCallback callback =delegate(object dummy){m_mainWindow.NotifyMessage(message);};m_uiSyncContext.Post(callback, message);}public bool AcceptCall(string username){//调獭?用?线?程ì必?须?为a STA,?因皑?为a许í多à UI 组哩?件t都?需è要癮。£return MessageBox.Show(String.Format("Accep call from \"{0}\" ", username), "Incomming Call", MessageBoxButton.YesNo, MessageBoxImage.Information) == MessageBoxResult.Yes;}}
效果:
1、服务端登陆:
 
2、客户端登录:
 
3、文字聊天
 

4、共享白板:

总结:这篇文章实现了WPF的UI界面以及文字聊天和共享白板的功能。下一篇文章中将在此基础上实现语音通话的功能。

参考文章:

WXWinter的Silverlight例子_多人手写讨论板

Tim Callaghan, Alvin LimDrawMeWCF

附代码下载:http://files.cnblogs.com/zhuqil/ZqlChart.rar

(全文完)


以下为广告部分

您部署的HTTPS网站安全吗?

如果您想看下您的网站HTTPS部署的是否安全,花1分钟时间来 myssl.com 检测以下吧。让您的HTTPS网站变得更安全!

SSL检测评估

快速了解HTTPS网站安全情况。

安全评级(A+、A、A-...)、行业合规检测、证书信息查看、证书链信息以及补完、服务器套件信息、证书兼容性检测等。

SSL证书工具

安装部署SSL证书变得更方便。

SSL证书内容查看、SSL证书格式转换、CSR在线生成、SSL私钥加解密、CAA检测等。

SSL漏洞检测

让服务器远离SSL证书漏洞侵扰

TLS ROBOT漏洞检测、心血漏洞检测、FREAK Attack漏洞检测、SSL Poodle漏洞检测、CCS注入漏洞检测。

转载于:https://www.cnblogs.com/zhuqil/archive/2010/06/06/1752525.html

WPF+WCF一步一步打造音频聊天室(二):文字聊天和白板共享相关推荐

  1. WPF+WCF一步一步打造音频聊天室(三):语音聊天

    前一篇文章中实现了文字聊天和共享白板的功能,这篇文章中,我将在前一篇文章的基础上实现语音聊天的功能.语音聊天要比文字聊天和共享白板难度要大一点. 实现的大概的流程为: 1.一个聊天室成员向另外一个成员 ...

  2. wpf 语音通话_WPF+WCF一步一步打造音频聊天室(三):语音聊天

    前一篇文章中实现了文字聊天和共享白板的功能,这篇文章中,我将在前一篇文章的基础上实现语音聊天的功能.语音聊天要比文字聊天和共享白板难度要大一点. 实现的大概的流程为: 1.一个聊天室成员向另外一个成员 ...

  3. 从0搭建在线聊天室,只需4步!

    Vol. 5 聊天室不同于单聊和群聊,是一类集成了多种 IM 功能一体的大规模实时消息分发系统.在跨入新世纪的2000年,聊天室作为新型的即时通讯场景迅速在年轻人群体中火热起来,"网易聊天室 ...

  4. 一步一步实现直播和弹幕

    序言 最近在研究直播的弹幕,东西有点多,准备记录一下免得自己忘了又要重新研究,也帮助有这方面需要的同学少走点弯路.关于直播的技术细节其实就是两个方面一个是推流一个是拉流,而弹幕的实现核心在即时聊天,使 ...

  5. 嘿从零开始基于SpringBoot 打造在线聊天室(4.4W字最长博文)

    文章目录 前言 效果 主页面 消息提示 聊天页面 登录注册 前端 项目构建 依赖 项目结构 登录注册 验证码部分 登录页面 注册页面 主页面 流程 websocket loadmessage 消息发送 ...

  6. 网易云信联手配音秀,打造语音聊天室互动新体验

    自互联网走进这个时代起,我们生活的方方面面都在不断发生改变,文化娱乐是其中之一.从网文.网游.网剧,到网综.短视频.在线演唱会,互联网不仅丰富了我们的娱乐方式,也改变了整个文娱产业格局.借着互联网的东 ...

  7. websocket以及nodejs联手打造的类qq群聊天室 教程 附 原代码

    这次给大家分享的是我自己开发的多人聊天室,利用websocket 以及服务器端使用node.js 来让用户不需要刷新浏览器就可以获得实时更新. 如下面图所示的样子.开发出类QQ群聊天室的主界面,当然U ...

  8. vue php聊天室,Laravel + Swoole 打造IM简易聊天室

    Laravel + Swoole 打造IM简易聊天室 最近在学习Swoole,利用Swoole扩展让PHP生动了不少,本篇就来Swoole开发一款简易的IM聊天室 应用场景:实现简单的即时消息聊天室. ...

  9. 肝了一夜!我用Python打造了一款武林外传QQ聊天室

    公众号 "菜鸟学Python" 第439篇原创,设为 "星标",一起学Python! 大家在平时的学习或者是生活中,想必都少不了群聊,无论是微信还是QQ,都有群 ...

  10. WPF+WCF一步一步打造音频聊天室(一):概述

    前几天在老徐的MSN群中聊WCF.我突然想到了用WPF和WCF来打造音频聊天室这么一个轮子.其实是这样的,我在的公司是两岸三地合作开发的.两岸是指大陆和台湾,三地是指深圳.台北.高雄.由于公司很小,所 ...

最新文章

  1. Xamarin XAML语言教程Visual Studio中实现XAML预览
  2. POJ 1039 Pipe
  3. python教程视频在线-微软再推免费在线Python教程 包含20个视频
  4. git的简单操作命令
  5. 在Spring MVC Web应用程序中添加社交登录:单元测试
  6. 二维温度场matlab编程,二维温度场重建算法(价钱可议)
  7. Redhat与ubuntu配置网卡
  8. virtualbox启用远程桌面
  9. Jmeter系列之常用组件(一)
  10. 通达信公式-涨幅限制
  11. 如何将php文件通过后台导入,如何将通过url传到php后台的json在后台再次转换为json格式?...
  12. jenkins 基础配置安装(Ⅰ)
  13. petalinux设计——使用petalinux定制linux系统
  14. 通过Nginx搭建flv流媒体服务器
  15. php 牛顿冷却定律,基于用户投票的排名算法(四):牛顿冷却定律
  16. 清橙OJ A1035 素数之和
  17. 武汉青少年计算机编程,武汉青少年编程学习
  18. 设计按钮、下拉框、文本框的测试用例要点
  19. 关于数据库加密你不能不知道的秘密
  20. 手把手教你写一个基于python+pyqt5的股票盯盘软件

热门文章

  1. android录音波浪动画_Android实现波浪效果 - WaveView
  2. Ceres Solver从零开始手把手教学使用
  3. 51单片机教程:8*8 点阵显示字符、数字、简单汉字
  4. 工程制图 ( 制图的基本知识和基本技能)
  5. 计算机科学与技术统考专业代码,考试类别和级别及专业及科目代码表.doc
  6. 第六章 网络学习相关技巧2(权重设置)
  7. Java环境安装(Linux版)
  8. 学术-数学:费马猜想
  9. Ubuntu桌面不见了,桌面找回
  10. python爬取discuz_爬虫技术实践(二)Discuz! 按板块爬取帖子内容实战