程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> WPF+WCF一步一步打造音頻聊天室(二):文字聊天和白板共享

WPF+WCF一步一步打造音頻聊天室(二):文字聊天和白板共享

編輯:關於.NET

這篇文章將講述實現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 clients
                         callbackClient.ServerDisconnected();
                     }
                 }
                 else
                 {
                     //normal user logout
                     callbackClient.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界面以及文字聊天和共享白板的功能。下一篇文章中將在此基礎上實現語音通話的功能。

出處:http://zhuqil.cnblogs.com

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved