搭建QQ聊天通信的程序:(1)基于 networkcomms.net 创建一个WPF聊天客户端服务器应用程序 (1)

搭建QQ聊天通信的程序:(1)基于 networkcomms.net 创建一个WPF聊天客户端服务器应用程序

原文地址(英文):http://www.networkcomms.net/creating-a-wpf-chat-client-server-application/

注意:本教程是相当广泛的,如果你是在短请也看到我们的东西 开始如何在几分钟内创建一个客户端服务器应用程序教程。

注2:本例中包括,明显延长进一步证明功能,在包中包含的示例 包下载

在我们开始之前确保您已经安装了Visual Studio 2010中表达或晚,这应该有 .net4.0 或更高版本。

1。 创建Visual Studio项目

  • 创建一个新的包含visual c# visual studio解决方案的 WPF应用程序 “项目命名它” WPFChatExample
  • 右键单击项目刚刚创建,选择“ 属性 ”。 确保的 目标框架 “是” .net4.0“而不是” 。 .net4.0客户端配置文件 ”。 你现在应该有这样的。

新鲜的visual studio创建应用程序命名为“WPFChatExample”

2。 添加NetworkComms.net DLL项目

  • NetworkComms.Net 下载包包含DLL在所有支持的平台上,但我们感兴趣的只是.net4.0>>发布完整的DLL。 这个DLL复制到相同的位置,我们在步骤1中创建的解决方案。
  • 我们现在需要添加一个项目引用NetworkComms。 净DLL我们只是补充道。 右键单击“ WPFChatExample “项目并选择” 添加引用… ”。 在打开的窗口中选择Browse选项卡并选择我们刚刚添加的DLL。
  • 如果你扩大 引用 文件夹内的项目你现在应该看到NetworkComms。 净参考你就像这样:

“WPFChatExample”WPF应用程序包含一个引用NetworkComms完成.net DLL。

3所示。 添加WPF元素

  • 我们需要添加文本框和按钮,我们打算与WPF布局。 双击“开始 MainWindow.xaml 的文件,主要查看器中打开:

开放的主窗口。 xaml文件显示‘设计’和‘xaml”。

  • 如果你想,你可以现在添加每个文本框和按钮。 为了节省时间但是我们提供了一个基础布局,您可以复制和粘贴。 复制并粘贴以下代码来替代所有现有的代码在XAML视图 MainWindow.xaml ”:

c#

 1 <Window x:Class="WPFChatExample.MainWindow"
 2         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 3         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 4         Title="NetworkComms .Net WPF Chat Example" Height="341" Width="512" Background="#FF7CA0FF" ResizeMode="CanMinimize">
 5     <Grid>
 6         <TextBox Height="23" HorizontalAlignment="Left" Margin="68,8,0,0" Name="serverIP" VerticalAlignment="Top" Width="97" />
 7         <Label Content="Server IP:" Height="28" HorizontalAlignment="Left" Margin="8,6,0,0" Name="label1" VerticalAlignment="Top" />
 8         <TextBox Height="23" HorizontalAlignment="Left" Margin="199,8,0,0" Name="serverPort" VerticalAlignment="Top" Width="47" />
 9         <Label Content="Port:" Height="28" HorizontalAlignment="Left" Margin="166,6,0,0" Name="label2" VerticalAlignment="Top" />
10         <TextBox Height="231" HorizontalAlignment="Left" Margin="11,38,0,0" Name="chatBox" VerticalAlignment="Top" Width="356" IsReadOnly="True" VerticalScrollBarVisibility="Visible" />
11         <Label Content="Messages from:" Height="28" HorizontalAlignment="Left" Margin="369,84,0,0" Name="label3" VerticalAlignment="Top" Width="98" />
12         <TextBox Height="161" HorizontalAlignment="Left" Margin="373,108,0,0" Name="messagesFrom" VerticalAlignment="Top" Width="117" IsReadOnly="True" VerticalScrollBarVisibility="Auto" />
13         <Label Content="Local Name:" Height="28" HorizontalAlignment="Left" Margin="293,7,0,0" Name="label4" VerticalAlignment="Top" />
14         <TextBox Height="23" HorizontalAlignment="Left" Margin="373,8,0,0" Name="localName" VerticalAlignment="Top" Width="117" />
15         <Label Content="Message:" Height="28" HorizontalAlignment="Left" Margin="5,272,0,0" Name="label5" VerticalAlignment="Top" />
16         <TextBox Height="23" HorizontalAlignment="Left" Margin="62,274,0,0" Name="messageText" VerticalAlignment="Top" Width="305" />
17         <Button Content="Send" Height="23" HorizontalAlignment="Left" Margin="373,274,0,0" Name="sendMessageButton" VerticalAlignment="Top" Width="117"/>
18         <CheckBox Content="Enable Server" Height="16" HorizontalAlignment="Left" Margin="377,44,0,0" x:Name="enableServer" VerticalAlignment="Top"/>
19         <CheckBox Content="Use Encryption" Height="16" HorizontalAlignment="Left" Margin="377,65,0,0" Name="useEncryptionBox" VerticalAlignment="Top"/>
20     </Grid>
21 </Window>

  • 设计窗口现在应该显示相当于你刚从上面贴的XAML。 这给了我们的基本布局聊天应用程序:

后复制粘贴的例子xaml代码设计窗口现在应该显示的基本布局。

  • 媒体对你的键盘的F5′,确保项目成功构建(即错误列表窗口在Visual studio仍然是空的)。 如果项目不建立在这一点上请回去在本教程中,确保您已经完成了所有的必要步骤。 如果项目构建你现在应该看到WPF应用程序,当然,我们仍然需要添加的所有功能。

WPF聊天应用程序的例子。 所有的布局元素添加了但是没有任何功能。

4所示。 添加ChatMessage包装类

  • 下一步是创建一个包装器类的消息我们将发送和接收,即一个对象我们发送和接收包含所有必要的信息。 右键单击该项目并选择“ 添加 “>” 新项目… ”。 这应该引出的 添加新项 窗口中,一个选项列表,你可以添加到项目中。 确保的 ”项被选中时,在窗口的底部输入名称” ChatMessage.cs ”。 现在点击“ 添加 ”。 新的类文件应该自动打开,你现在应该是这样的:

这个新类,名为“ChatMessage.cs”。 这将是用作聊天信息的包装器。

  • 复制并粘贴以下代码,取代现有的所有代码在我们刚刚创建的类,“ ChatMessage.cs ”:
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5
 6 //我们需要包括以下三本类的命名空间 7 using NetworkCommsDotNet;
 8 using NetworkCommsDotNet.Tools;
 9 using ProtoBuf;
10
11 namespace WPFChatExample
12 {
13     /// <summary>
14     /// A wrapper class for the messages that we intend to send and receive.
15     /// The [ProtoContract] attribute informs NetworkComms .Net that we intend to
16     /// serialise(连载) (turn into bytes) this object. At the base level the
17     /// serialisation(连载) is performed by protobuf.net.
18     /// </summary>
19     [ProtoContract]
20     class ChatMessage
21     {
22         /// <summary>
23         /// chatmessage标识源.
24         /// We use this variable as the constructor for the ShortGuid.
25         /// The [ProtoMember(1)] attribute informs the serialiser that when
26         /// an object of type ChatMessage is serialised we want to include this variable
27         /// </summary>
28         [ProtoMember(1)]
29         string _sourceIdentifier;
30
31         /// <summary>
32         /// The source identifier is accessible as a ShortGuid
33         /// </summary>
34         public ShortGuid SourceIdentifier { get { return new ShortGuid(_sourceIdentifier); } }
35
36         /// <summary>
37         /// The name of the source of this ChatMessage.
38         /// We use shorthand declaration, get and set.
39         /// The [ProtoMember(2)] attribute informs the serialiser that when
40         /// an object of type ChatMessage is serialised we want to include this variable
41         /// </summary>
42         [ProtoMember(2)]
43         public string SourceName { get; private set; }
44
45         /// <summary>
46         /// The actual message.
47         /// </summary>
48         [ProtoMember(3)]
49         public string Message { get; private set; }
50
51         /// <summary>
52         /// The index of this message. Every message sent by a particular source
53         /// has an incrementing(增值) index.
54         /// </summary>
55         [ProtoMember(4)]
56         public long MessageIndex { get; private set; }
57
58         /// <summary>
59         /// The number of times this message has been relayed.
60         /// </summary>
61         [ProtoMember(5)]
62         public int RelayCount { get; private set; }
63
64         /// <summary>
65         /// We must include a private constructor to be used by the deserialisation step.
66         /// </summary>
67         private ChatMessage() { }
68
69         /// <summary>
70         /// Create a new ChatMessage
71         /// </summary>
72         /// <param name="sourceIdentifier">The source identifier</param>
73         /// <param name="sourceName">The source name</param>
74         /// <param name="message">The message to be sent</param>
75         /// <param name="messageIndex">The index of this message</param>
76         public ChatMessage(ShortGuid sourceIdentifier, string sourceName, string message, long messageIndex)
77         {
78             this._sourceIdentifier = sourceIdentifier;
79             this.SourceName = sourceName;
80             this.Message = message;
81             this.MessageIndex = messageIndex;
82             this.RelayCount = 0;
83         }
84
85         /// <summary>
86         /// Increment the relay count variable
87         /// </summary>
88         public void IncrementRelayCount()
89         {
90             RelayCount++;
91         }
92     }
93 }

5。 将功能添加到代码元素MainWindow.xaml

  • 现在我们将注意力转向的代码元素 MainWindow.xaml ”。 右键单击访问代码元素的 MainWindow.xaml ”,选择“ 视图代码 从上下文菜单中。 您应该看到一个代码文件,其中包含之前,所有的代码我们随后要添加将在 主窗口 类:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Windows;
 6 using System.Windows.Controls;
 7 using System.Windows.Data;
 8 using System.Windows.Documents;
 9 using System.Windows.Input;
10 using System.Windows.Media;
11 using System.Windows.Media.Imaging;
12 using System.Windows.Navigation;
13 using System.Windows.Shapes;
14
15 namespace WPFChatExample
16 {
17     /// <summary>
18     /// Interaction logic for MainWindow.xaml
19     /// </summary>
20     public partial class MainWindow : Window
21     {
22         public MainWindow()
23         {
24             InitializeComponent();
25         }
26     }
27 }

MainWindow.xaml

  • 因为我们要执行网络任务在这门课中,我们首先需要添加相关的名称空间引用。 下面所有的 使用系统… “您想要添加名称空间引用:
1 //We need to include the following namespaces
2 using System.Net;
3 using NetworkCommsDotNet;
4 using NetworkCommsDotNet.DPSBase;
5 using NetworkCommsDotNet.Tools;
6 using NetworkCommsDotNet.Connections;
7 using NetworkCommsDotNet.Connections.TCP;
  • 接下来我们要添加一些类变量来帮助我们跟踪当前应用程序状态。 我们想跟踪:
  1. 我们已经收到最新消息。
  2. 最大数量的时候我们将传递一个信息。
  3. 一个可选的加密密钥。
  4. 本地索引时我们将使用发送新消息。
  • 跟踪这些项目添加以下代码的类:
 1 #region Private Fields
 2 /// <summary>
 3 /// Dictionary to keep track of which peer messages have already been written to the chat window
 4 /// </summary>
 5 Dictionary<ShortGuid, ChatMessage> lastPeerMessageDict = new Dictionary<ShortGuid, ChatMessage>();
 6
 7 /// <summary>
 8 /// The maximum number of times a chat message will be relayed
 9 /// </summary>
10 int relayMaximum = 3;
11
12 /// <summary>
13 /// An optional encryption key to use should one be required.
14 /// This can be changed freely but must obviously be the same
15 /// for both sender and receiver.
16 /// </summary>
17 string encryptionKey = "ljlhjf8uyfln23490jf;m21-=scm20--iflmk;";
18
19 /// <summary>
20 /// A local counter used to track the number of messages sent from
21 /// this instance.
22 /// </summary>
23 long messageSendIndex = 0;
24 #endregion
  • 接下来,我们将添加的方法使用WPF GUI。 前两个方法可用于从任何线程更新聊天和MessageFrom文本框:

 1 /// <summary>
 2 /// Append the provided message to the chatBox text box.
 3 /// </summary>
 4 /// <param name="message"></param>
 5 private void AppendLineToChatBox(string message)
 6 {
 7     //To ensure we can successfully append to the text box from any thread
 8     //we need to wrap the append within an invoke action.
 9     chatBox.Dispatcher.BeginInvoke(new Action<string>((messageToAdd) =>
10     {
11         chatBox.AppendText(messageToAdd + "\n");
12         chatBox.ScrollToEnd();
13     }), new object[] { message });
14 }
15
16 /// <summary>
17 /// Refresh the messagesFrom text box using the recent message history.
18 /// </summary>
19 private void RefreshMessagesFromBox()
20 {
21     //We will perform a lock here to ensure the text box is only
22     //updated one thread at  time
23     lock (lastPeerMessageDict)
24     {
25         //Use a linq expression to extract an array of all current users from lastPeerMessageDict
26         string[] currentUsers = (from current in lastPeerMessageDict.Values orderby current.SourceName select current.SourceName).ToArray();
27
28         //To ensure we can successfully append to the text box from any thread
29         //we need to wrap the append within an invoke action.
30         this.messagesFrom.Dispatcher.BeginInvoke(new Action<string[]>((users) =>
31         {
32             //First clear the text box
33             messagesFrom.Text = "";
34
35             //Now write out each username
36             foreach (var username in users)
37                 messagesFrom.AppendText(username + "\n");
38         }), new object[] { currentUsers });
39     }
40 }

  • 接下来下有五个方法将被附加到WPF元素布局在步骤6。 他们将被用来发送消息,切换加密,本地服务器模式开关并正确地关闭一切当我们完成了对应用程序:

 1 /// <summary>
 2 /// Send any entered message when we click the send button.
 3 /// </summary>
 4 /// <param name="sender"></param>
 5 /// <param name="e"></param>
 6 private void SendMessageButton_Click(object sender, RoutedEventArgs e)
 7 {
 8     SendMessage();
 9 }
10
11 /// <summary>
12 /// Send any entered message when we press enter or return
13 /// </summary>
14 /// <param name="sender"></param>
15 /// <param name="e"></param>
16 private void MessageText_KeyUp(object sender, KeyEventArgs e)
17 {
18     if (e.Key == Key.Enter || e.Key == Key.Return)
19         SendMessage();
20 }
21
22 /// <summary>
23 /// Toggle encryption
24 /// </summary>
25 /// <param name="sender"></param>
26 /// <param name="e"></param>
27 private void UseEncryptionBox_CheckedToggle(object sender, RoutedEventArgs e)
28 {
29     if (useEncryptionBox.IsChecked != null && (bool)useEncryptionBox.IsChecked)
30     {
31         RijndaelPSKEncrypter.AddPasswordToOptions(NetworkComms.DefaultSendReceiveOptions.Options, encryptionKey);
32         NetworkComms.DefaultSendReceiveOptions.DataProcessors.Add(DPSManager.GetDataProcessor<RijndaelPSKEncrypter>());
33     }
34     else
35         NetworkComms.DefaultSendReceiveOptions.DataProcessors.Remove(DPSManager.GetDataProcessor<RijndaelPSKEncrypter>());
36 }
37
38 /// <summary>
39 /// Correctly shutdown NetworkComms .Net when closing the WPF application
40 /// </summary>
41 /// <param name="sender"></param>
42 /// <param name="e"></param>
43 private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
44 {
45     //Ensure we shutdown comms when we are finished
46     NetworkComms.Shutdown();
47 }
48
49 /// <summary>
50 /// Toggle whether the local application is acting as a server
51 /// </summary>
52 /// <param name="sender"></param>
53 /// <param name="e"></param>
54 private void EnableServer_Toggle(object sender, RoutedEventArgs e)
55 {
56     //Enable or disable the local server mode depending on the checkbox IsChecked value
57     if (enableServer.IsChecked != null && (bool)enableServer.IsChecked)
58         ToggleServerMode(true);
59     else
60         ToggleServerMode(false);
61 }

  • 接下来我们添加的方法可以用来切换应用程序的本地服务器模式:

 1 /// <summary>
 2 /// Wrap the functionality required to enable/disable the local application server mode
 3 /// </summary>
 4 /// <param name="enableServer"></param>
 5 private void ToggleServerMode(bool enableServer)
 6 {
 7     if (enableServer)
 8     {
 9         //Start listening for new incoming TCP connections
10         //Parameters ensure we listen across all adaptors using a random port
11         Connection.StartListening(ConnectionType.TCP, new IPEndPoint(IPAddress.Any, 0));
12
13         //Write the IP addresses and ports that we are listening on to the chatBox
14         chatBox.AppendText("Listening for incoming TCP connections on:\n");
15         foreach (IPEndPoint listenEndPoint in Connection.ExistingLocalListenEndPoints(ConnectionType.TCP))
16             chatBox.AppendText(listenEndPoint.Address + ":" + listenEndPoint.Port + "\n");
17     }
18     else
19     {
20         NetworkComms.Shutdown();
21         chatBox.AppendText("Server disabled. No longer accepting connections and all existing connections have been closed.");
22     }
23 }

  • 接下来,我们将创建一个方法,可以通过NetworkComms执行。 网络聊天消息时已经收到。 在此方法中,我们可以把任何我们想做的但是因为我们正在聊天应用程序可能希望的方法:
  1. 打印消息ChatBox文本框。
  2. 从文本框更新消息。
  3. 传递消息给其他同行。
  • 可以执行这些功能的方法如下:

 1 /// <summary>
 2 /// Performs whatever functions we might so desire when we receive an incoming ChatMessage
 3 /// </summary>
 4 /// <param name="header">The PacketHeader corresponding with the received object</param>
 5 /// <param name="connection">The Connection from which this object was received</param>
 6 /// <param name="incomingMessage">The incoming ChatMessage we are after</param>
 7 private void HandleIncomingChatMessage(PacketHeader header, Connection connection, ChatMessage incomingMessage)
 8 {
 9     //We only want to write a message once to the chat window
10     //Because we allow relaying and may receive the same message twice
11     //we use our history and message indexes to ensure we have a new message
12     lock (lastPeerMessageDict)
13     {
14         if (lastPeerMessageDict.ContainsKey(incomingMessage.SourceIdentifier))
15         {
16             if (lastPeerMessageDict[incomingMessage.SourceIdentifier].MessageIndex < incomingMessage.MessageIndex)
17             {
18                 //If this message index is greater than the last seen from this source we can safely
19                 //write the message to the ChatBox
20                 AppendLineToChatBox(incomingMessage.SourceName + " - " + incomingMessage.Message);
21
22                 //We now replace the last received message with the current one
23                 lastPeerMessageDict[incomingMessage.SourceIdentifier] = incomingMessage;
24             }
25         }
26         else
27         {
28             //If we have never had a message from this source before then it has to be new
29             //by definition
30             lastPeerMessageDict.Add(incomingMessage.SourceIdentifier, incomingMessage);
31             AppendLineToChatBox(incomingMessage.SourceName + " - " + incomingMessage.Message);
32         }
33     }
34
35     //Once we have written to the ChatBox we refresh the MessagesFromWindow
36     RefreshMessagesFromBox();
37
38     //This last section of the method is the relay function
39     //We start by checking to see if this message has already been relayed
40     //the maximum number of times
41     if (incomingMessage.RelayCount < relayMaximum)
42     {
43         //If we are going to relay this message we need an array of
44         //all other known connections
45         var allRelayConnections = (from current in NetworkComms.GetExistingConnection() where current != connection select current).ToArray();
46
47         //We increment(增量) the relay count before we send
48         incomingMessage.IncrementRelayCount();
49
50         //We will now send the message to every other connection
51         foreach (var relayConnection in allRelayConnections)
52         {
53             //We ensure we perform the send within a try catch
54             //To ensure a single failed send will not prevent the
55             //relay to all working connections.
56             try { relayConnection.SendObject("ChatMessage", incomingMessage); }
57             catch (CommsException) { /* Catch the comms exception, ignore and continue */ }
58         }
59     }
60 }

  • NetworkComms。 网有一个广泛的功能和使用情况。 其中一个允许您执行代码每次连接断开连接。 在这个例子中,我们将创建一个方法写ChatBox断开的消息。 方法如下:

 1 /// <summary>
 2 /// Performs whatever functions we might so desire when an existing connection is closed.
 3 /// </summary>
 4 /// <param name="connection">The closed connection</param>
 5 private void HandleConnectionClosed(Connection connection)
 6 {
 7     //We are going to write a message to the ChatBox when a user disconnects
 8     //We perform the following within a lock so that threads proceed one at a time
 9     lock (lastPeerMessageDict)
10     {
11         //Extract the remoteIdentifier from the closed connection
12         ShortGuid remoteIdentifier = connection.ConnectionInfo.NetworkIdentifier;
13
14         //If at some point we received a message with this identifier we can
15         //include the source name in the disconnection message.
16         if (lastPeerMessageDict.ContainsKey(remoteIdentifier))
17             AppendLineToChatBox("Connection with ‘" + lastPeerMessageDict[remoteIdentifier].SourceName + "‘ has been closed.");
18         else
19             AppendLineToChatBox("Connection with ‘" + connection.ToString() + "‘ has been closed.");
20
21         //Last thing is to remove this entry from our message history
22         lastPeerMessageDict.Remove(connection.ConnectionInfo.NetworkIdentifier);
23     }
24
25     //Refresh the messages from box to reflect this disconnection
26     RefreshMessagesFromBox();
27 }

下一个方法将用于发送任何消息,我们创建:

 1 /// <summary>
 2 /// Send our message.
 3 /// </summary>
 4 private void SendMessage()
 5 {
 6     //If we have tried to send a zero length string we just return
 7     if (messageText.Text.Trim() == "") return;
 8
 9     //We may or may not have entered some server connection information
10     ConnectionInfo serverConnectionInfo = null;
11     if (serverIP.Text != "")
12     {
13         try { serverConnectionInfo = new ConnectionInfo(serverIP.Text.Trim(), int.Parse(serverPort.Text)); }
14         catch (Exception)
15         {
16             MessageBox.Show("Failed to parse the server IP and port. Please ensure it is correct and try again", "Server IP & Port Parse Error", MessageBoxButton.OK);
17             return;
18         }
19     }
20
21     //We wrap everything we want to send in the ChatMessage class we created
22     ChatMessage messageToSend = new ChatMessage(NetworkComms.NetworkIdentifier, localName.Text, messageText.Text, messageSendIndex++);
23
24     //We add our own message to the message history in-case it gets relayed back to us
25     lock (lastPeerMessageDict) lastPeerMessageDict[NetworkComms.NetworkIdentifier] = messageToSend;
26
27     //We write our own message to the chatBox
28     AppendLineToChatBox(messageToSend.SourceName + " - " + messageToSend.Message);
29
30     //We refresh the MessagesFrom box so that it includes our own name
31     RefreshMessagesFromBox();
32
33     //We clear the text within the messageText box.
34     this.messageText.Text = "";
35
36     //If we provided server information we send to the server first
37     if (serverConnectionInfo != null)
38     {
39         //We perform the send within a try catch to ensure the application continues to run if there is a problem.
40         try { TCPConnection.GetConnection(serverConnectionInfo).SendObject("ChatMessage", messageToSend); }
41         catch (CommsException) { MessageBox.Show("A CommsException occurred while trying to send message to " + serverConnectionInfo, "CommsException", MessageBoxButton.OK); }
42     }
43
44     //If we have any other connections we now send the message to those as well
45     //This ensures that if we are the server everyone who is connected to us gets our message
46     var otherConnectionInfos = (from current in NetworkComms.AllConnectionInfo() where current != serverConnectionInfo select current).ToArray();
47     foreach (ConnectionInfo info in otherConnectionInfos)
48     {
49         //We perform the send within a try catch to ensure the application continues to run if there is a problem.
50         try { TCPConnection.GetConnection(info).SendObject("ChatMessage", messageToSend); }
51         catch (CommsException) { MessageBox.Show("A CommsException occurred while trying to send message to " + info, "CommsException", MessageBoxButton.OK); }
52     }
53 }

  • 最后我们需要添加的代码元素内的 MainWindow.xaml NetworkComms。net的是正确的初始化。 为了正确地初始化NetworkComms。 Net我们需要:
  1. 我们的机器的主机名设置默认本地名称。
  2. 触发的方法 HandleIncomingMessage “当我们收到一包类型” ChatMessage ”。
  3. 触发的方法 HandleConnectionClosed 当一个现有的连接关闭。
  • 我们在主窗口类构造函数执行这些初始化任务,代之以下面的代码:

 1 public MainWindow()
 2 {
 3     InitializeComponent();
 4
 5     //Write the IP addresses and ports that we are listening on to the chatBox
 6     chatBox.AppendText("Initialised WPF chat example.");
 7
 8     //Add a blank line after the initialisation output
 9     chatBox.AppendText("\n");
10
11     //Set the default Local Name box using to the local host name
12     localName.Text = HostInfo.HostName;
13
14     //Configure NetworkComms .Net to handle and incoming packet of type ‘ChatMessage‘
15     //e.g. If we receive a packet of type ‘ChatMessage‘ execute the method ‘HandleIncomingChatMessage‘
16     NetworkComms.AppendGlobalIncomingPacketHandler<ChatMessage>("ChatMessage", HandleIncomingChatMessage);
17
18     //Configure NetworkComms .Net to perform an action when a connection is closed
19     //e.g. When a connection is closed execute the method ‘HandleConnectionClosed‘
20     NetworkComms.AppendGlobalConnectionCloseHandler(HandleConnectionClosed);
21 }

6。 将事件添加到WPF布局

  • 应用程序的最后一步是添加必要的事件,这样按钮和文本框的布局可以用来发送消息。 这是通过编辑XAML的主窗口。 这是本教程的步骤3中相同的XAML编辑,但回顾一下,访问XAML通过双击 MainWindow.xaml 在解决方案资源管理器窗口中。
  • 当应用程序关闭Window_Closing我们想运行方法。 取代XAML的顶部部分目前是这样的:
1 <Window x:Class="WPFChatExample.MainWindow"
2         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4         Title="NetworkComms .Net WPF Chat Example" Height="341" Width="512" Background="#FF7CA0FF" ResizeMode="CanMinimize">

这个(注意添加关闭=“Window_Closing”结束时):

1 <Window x:Class="WPFChatExample.MainWindow"
2         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4         Title="NetworkComms .Net WPF Chat Example" Height="341" Width="512" Background="#FF7CA0FF" ResizeMode="CanMinimize" Closing="Window_Closing">
  • 我们想要一个当我们点击“发送消息 发送 ”按钮。 我们通过更换连接:
<Button Content="Send" Height="23" HorizontalAlignment="Left" Margin="373,274,0,0" Name="sendMessageButton" VerticalAlignment="Top" Width="117" />

这里以下排版不是很好,太晚了看花眼了,请参照原文(英文)

  • 我们希望用户能够输入后按回车或返回发送消息的消息框。 我们通过更换连接:
1 <Button Content="Send" Height="23" HorizontalAlignment="Left" Margin="373,274,0,0" Name="sendMessageButton" VerticalAlignment="Top" Width="117" Click="SendMessageButton_Click"/>
  • 接下来,我们需要添加事件检查,取消勾选“启用服务器”蜱虫盒。 我们通过更换连接:

这里以下排版不是很好,太晚了看花眼了,请参照原文(英文)

1 <Button Content="Send" Height="23" HorizontalAlignment="Left" Margin="373,274,0,0" Name="sendMessageButton" VerticalAlignment="Top" Width="117" Click="SendMessageButton_Click"/>
1 <TextBox Height="23" HorizontalAlignment="Left" Margin="62,274,0,0" Name="messageText" VerticalAlignment="Top" Width="305" />
1 <TextBox Height="23" HorizontalAlignment="Left" Margin="62,274,0,0" Name="messageText" VerticalAlignment="Top" Width="305" KeyUp="MessageText_KeyUp"/>
1 <CheckBox Content="Enable Server" Height="16" HorizontalAlignment="Left" Margin="377,44,0,0" x:Name="enableServer" VerticalAlignment="Top" />

1 <CheckBox Content="Use Encryption" Height="16" HorizontalAlignment="Left" Margin="377,65,0,0" Name="useEncryptionBox" VerticalAlignment="Top" />
  • 最后,我们需要添加的事件检查和取消勾选“ 使用加密 “蜱虫盒。 我们通过更换线:
1 <CheckBox Content="Use Encryption" Height="16" HorizontalAlignment="Left" Margin="377,65,0,0" Name="useEncryptionBox" VerticalAlignment="Top" Checked="UseEncryptionBox_CheckedToggle" Unchecked="UseEncryptionBox_CheckedToggle" />
  • 就是这样。 现在,我们可以看到我们的努力。

7所示。 测试你的WPF聊天应用程序

  • 我们终于抵达了测试阶段。 我们现在要开至少两个WPF聊天应用程序的实例。 要做到这一点,我们首先需要构建项目在调试模式下(确保Visual Studio显示的 调试 在顶部菜单),通过解决方案上单击右键并选择“ 构建解决方案 ”或紧迫的” F6 键盘上的。
  • 现在浏览到构建应用程序的位置。 一种方法是右键单击项目在Visual Studio,选择“ 在Windows资源管理器打开文件夹 ”。 寻找一个文件夹名为“ ”,在“ 调试 ”。
  • 现在,您应该看到一个可执行文件名为“ WPFChatExample.exe ”,双击这两次打开两个实例的例子。 注意:当你打开应用程序从你的系统防火墙可能会得到一个通知。 重要的是要提供必要的权限(见防火墙文档)否则将无法交流的例子。
  • 选择哪一个应用程序将作为一个服务器(指定的应用程序)。检查的 启用服务器 “tickbox。 该应用程序现在应该显示哪些ipaddress和港口可供连接:

完成应用程序的示例输出本地服务器后启用。

  • 选择一个合适的服务器IP地址和端口(通常127.0.0.1或192.168 . * . *)从应用程序A所示的输出和输入这些信息到其他应用程序(应用程序B)。
  • 现在消息输入到应用程序B并点击发送或按enter。 现在的消息将出现在两个应用程序。 一旦连接建立了以这种方式信息现在可以进入两个应用程序中,它就会出现在另一个。
  • 我们刚刚展示的是最基本的连接情况如下,以下应用程序B选择应用程序的服务器:

最基本的连接配置。 应用程序B已选定的应用程序服务器。

  • 我们可以添加另一个应用程序,还贴上C和指定服务器应用程序如下:

另一个基本的连接配置。 应用程序B已选定的应用程序服务器。 应用C也选择的应用程序服务器。

  • 我们可以变得更时髦的因为我们添加了继电器的功能。 而不是应用程序C指定应用程序的服务器可以设置应用程序C应用程序A .一旦应用程序连接的服务器以这种方式进入一个消息客户端C将传送通过B:

一个更先进的连接配置。 应用程序B已选定的应用程序服务器。 C应用程序已经选择的应用程序服务器。

  • 最后一个示例配置有三个应用程序设置他们的戒指。 C应用程序B使用应用服务器,应用程序C使用应用程序的服务器和应用程序使用应用程序B的服务器。 这个配置工作,因为我们有最大数量的继电器/消息和使用消息历史,以防止重复写入到聊天窗口:

最先进的连接配置使用三个客户。 选择应用程序B作为其服务器应用程序。 C应用程序B已经选定的应用程序服务器。 应用程序选择C应用程序的服务器。

如果一切工作

  • 如果你发现了这篇文章有用或有什么想法,我们可以如何改进,请给我们评论。

如果你有问题

  1. 确保您已经正确配置防火墙允许必要的交通。
  2. 如果你还有问题请上我们的 论坛我们将非常乐意帮助。

更多信息

  1. 看到我们的 开始基本的客户端服务器应用程序文章。
  2. 看到我们的网上 API参考这就解释了所有的方法做什么。
  3. 问我们的任何问题 论坛
时间: 2024-10-26 20:30:29

搭建QQ聊天通信的程序:(1)基于 networkcomms.net 创建一个WPF聊天客户端服务器应用程序 (1)的相关文章

(4opencv)如何基于GOCW,创建一个实时视频程序

直接使用提供的代码框架进行修改,是最快得到效果的方法:但是这样的灵活性较差,而且真正的程序员从来都不会停滞在这一步:我们需要的是"将框架解析到最小化.理清楚每个构建之间的关系",只有这样才能灵活运用. 一.准备工作 1.高拍仪已经接通,如果需要的话,还要安装驱动: 2.vs2012编程环境,能够编写Csharp和OpenCV程序(具体不清楚可以回过头来看配置): 3.是DirectShow.net(http://directshownet.sourceforge.net/docs.ht

微信小程序开发(一)创建一个小程序Hello World!

开发微信小程序并不是很难,网上有很多小程序开发资料,尤其是微信官方的<小程序开发指南>最详细. 下面是我开发小程序的历程: 第一步,请前往https://mp.weixin.qq.com/debug/wxadoc/dev/devtools/download.html 微信开发者工具下载页面根据自己的操作系统下载对应的安装包进行安装. 第二步,打开微信开发者工具,选择新建小程序项目. 红框里面可以选择 测试号 .AppID可以自己去注册.小程序使用js开发的,所以有js开发经验的很快就可以入门并

如何用Unity创建一个的简单的HoloLens 3D程序

注:本文提到的代码示例下载地址>How to create a Hello World 3D holographic app with Unity 之前我们有讲过一次如何在HoloLens中创建一个2D程序的,没看过或者忘记的同学可以看这里回忆一下^_^ 如果说上次的2D版就是个带了个HoloLens面具的UWP程序,那我们这次要做的呢可是正宗的3D程序哦. 先来看看我们要做些什么准备. 1. Visual Studio 2015 Update 3 2. Windows 10 (10.0.105

《程序员的呐喊》:一个熟悉多种语言的老程序员对编程语言、开发流程、google的战略等的思考,比较有趣。 五星推荐

作者熟悉二三十种编程语言,写了20多年代码.本书是作者对编程语言.开发流程.google的战略等的思考.比较有趣. 前面部分是作者对编程语言的一些思考.作者鄙视C++, Java,面向对象.比较有趣的是作者把编程语言和思想划分为自由和保守两大阵营.自由派希望快速发布,容忍bug和安全上的缺陷,保守派则重视安全和稳健 作者认为,设计优秀的弱类型系统比同样优秀的强类型系统更有竞争力. 作者推崇精简,认为代码最大的敌人是体格,也就是代码的行数. 作者认为Perl和Python两种语言的出现时间差不多,

【Java】使用JFrame监听事件创建一个复制文本功能的窗体程序与按钮快捷键

一.基本目标 设计一个窗体程序,有两个文本框,其中第二个文本框是不可编辑的,有三个按钮,点击Copy按钮能把第一个文本框复制到第二个文本框,点击Clear按钮能把两个文本框的内容清空,也可以用快捷键ALT+R与ALT+Y操作 点击Close按钮,能关闭这个窗体程序 二.基本思想 这个JFrame的布局与各组件名称如下,请联合下面的代码查看: 三.制作过程 请看如下代码: import java.awt.*; import java.awt.event.*; import javax.swing.

微信小程序开发(二)创建一个小程序页面

为了方便讲解,我们将上篇博客创建的小程序除了project.config.json和sitemap.json两个文件保留,其他全部删除(这两个文件存的是小程序的创建信息,删掉会有报错提示). 接下来我们创建如下文件,先不写内容. 写入如下代码: // app.js App({}) // 注册小程序 // index.js Page({}) // 注册页面 // app.json { "pages": [ "qrcode/index/index"  // 页面路径 ]

按要求编写Java应用程序。 (1)创建一个叫做People的类: 属性:姓名、年龄、性别、身高 行为:说话、计算加法、改名 编写能为所有属性赋值的构造方法; (2)创建主类: 创建一个对象:名叫“张三”,性别“男”,年龄18岁,身高1.80; 让该对象调用成员方法: 说出“你好!” 计算23+45的值 将名字改为“李四”

package java1; public class People { public String name; public int age; public String sex; public String height; People(String name, int age, String sex, String height) { this.name = name; this.age = age; this.sex = sex; this.height = height; } publ

按要求编写Java应用程序。 (1)创建一个叫做机动车的类: 属性:车牌号(String),车速(int),载重量(double) 功能:加速(车速自增)、减速(车速自减)、修改车牌号,查询车的载重量。 编写两个构造方法:一个没有形参,在方法中将车牌号设置“XX1234”,速 度设置为100,载重量设置为100;另一个能为对象的所有属性赋值; (2)创建主类: 在主类中创建两个机动车对象。 创建第

package com.hanqi.test; public class jidongche { private String chepaihao;//车牌号 private int speed;//速度 private double weight;//载重量 //无参构造方法 jidongche() { } public String getChepaihao() { return chepaihao; } public void setChepaihao(String chepaihao)

11.按要求编写Java应用程序。 (1)创建一个叫做机动车的类: 属性:车牌号(String),车速(int),载重量(double) 功能:加速(车速自增)、减速(车速自减)、修改车牌号,查询车的载重量。 编写两个构造方法:一个没有形参,在方法中将车牌号设置“XX1234”,速 度设置为100,载重量设置为100;另 一个能为对象的所有属性赋值; (2)创建主类: 在主类中创建两个机动车对象。

package java1; public class Che { //属性 public String nub; public int speed; public double weight ; Che() { nub="XX1234"; speed=100; weight=100; } Che(String nub, int speed,double weight) { this.nub = nub; this.speed = speed; this.weight = weight