转自:https://www.cnblogs.com/Soulless/p/7234352.html
首先创建 WPF Server 端,新建一个 WPF 项目
安装 Nuget 包
替换 MainWindows 的Xaml代码
<Window x:Class="WPFServer.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="WPF SignalR Server" Height="319" Width="343 "> <Grid><span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">Button </span><span style="color: rgba(255, 0, 0, 1)">x:Name</span><span style="color: rgba(0, 0, 255, 1)">="ButtonStart"</span><span style="color: rgba(255, 0, 0, 1)"> Content</span><span style="color: rgba(0, 0, 255, 1)">="Start"</span><span style="color: rgba(255, 0, 0, 1)"> HorizontalAlignment</span><span style="color: rgba(0, 0, 255, 1)">="Left"</span><span style="color: rgba(255, 0, 0, 1)"> Margin</span><span style="color: rgba(0, 0, 255, 1)">="10,10,0,0"</span><span style="color: rgba(255, 0, 0, 1)"> VerticalAlignment</span><span style="color: rgba(0, 0, 255, 1)">="Top"</span><span style="color: rgba(255, 0, 0, 1)"> Width</span><span style="color: rgba(0, 0, 255, 1)">="100"</span><span style="color: rgba(255, 0, 0, 1)"> Click</span><span style="color: rgba(0, 0, 255, 1)">="ButtonStart_Click"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">Button </span><span style="color: rgba(255, 0, 0, 1)">x:Name</span><span style="color: rgba(0, 0, 255, 1)">="ButtonStop"</span><span style="color: rgba(255, 0, 0, 1)"> Content</span><span style="color: rgba(0, 0, 255, 1)">="Stop"</span><span style="color: rgba(255, 0, 0, 1)"> HorizontalAlignment</span><span style="color: rgba(0, 0, 255, 1)">="Left"</span><span style="color: rgba(255, 0, 0, 1)"> Margin</span><span style="color: rgba(0, 0, 255, 1)">="225,10,0,0"</span><span style="color: rgba(255, 0, 0, 1)"> VerticalAlignment</span><span style="color: rgba(0, 0, 255, 1)">="Top"</span><span style="color: rgba(255, 0, 0, 1)"> Width</span><span style="color: rgba(0, 0, 255, 1)">="100"</span><span style="color: rgba(255, 0, 0, 1)"> Click</span><span style="color: rgba(0, 0, 255, 1)">="ButtonStop_Click"</span><span style="color: rgba(255, 0, 0, 1)"> IsEnabled</span><span style="color: rgba(0, 0, 255, 1)">="False"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">RichTextBox </span><span style="color: rgba(255, 0, 0, 1)">x:Name</span><span style="color: rgba(0, 0, 255, 1)">="RichTextBoxConsole"</span><span style="color: rgba(255, 0, 0, 1)"> HorizontalAlignment</span><span style="color: rgba(0, 0, 255, 1)">="Left"</span><span style="color: rgba(255, 0, 0, 1)"> Height</span><span style="color: rgba(0, 0, 255, 1)">="243"</span><span style="color: rgba(255, 0, 0, 1)"> Margin</span><span style="color: rgba(0, 0, 255, 1)">="10,35,0,0"</span><span style="color: rgba(255, 0, 0, 1)"> VerticalAlignment</span><span style="color: rgba(0, 0, 255, 1)">="Top"</span><span style="color: rgba(255, 0, 0, 1)"> Width</span><span style="color: rgba(0, 0, 255, 1)">="315"</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">FlowDocument</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">Paragraph</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">Paragraph</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">FlowDocument</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">RichTextBox</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">Grid</span><span style="color: rgba(0, 0, 255, 1)">></span>
</Window>
替换 MainWindows 后台代码
using Microsoft.AspNet.SignalR; using Microsoft.Owin.Cors; using Microsoft.Owin.Hosting; using Owin; using System; using System.Reflection; using System.Threading.Tasks; using System.Windows;
namespace WPFServer
{
/// <summary>
/// WPF host for a SignalR server. The host can stop and start the SignalR
/// server, report errors when trying to start the server on a URI where a
/// server is already being hosted, and monitor when clients connect and disconnect.
/// The hub used in this server is a simple echo service, and has the same
/// functionality as the other hubs in the SignalR Getting Started tutorials.
/// For simplicity, MVVM will not be used for this sample.
/// </summary>
public partial class MainWindow : Window
{
public IDisposable SignalR { get; set; }
const string ServerURI = “http://localhost:8080”;
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> MainWindow()
{
InitializeComponent();
}
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><summary></span>
<span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> Calls the StartServer method with Task.Run to not
</span><span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> block the UI thread.
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"></summary></span>
<span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">void</span> ButtonStart_Click(<span style="color: rgba(0, 0, 255, 1)">object</span><span style="color: rgba(0, 0, 0, 1)"> sender, RoutedEventArgs e)
{
WriteToConsole(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Starting server...</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
ButtonStart.IsEnabled </span>= <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">;
Task.Run(() </span>=><span style="color: rgba(0, 0, 0, 1)"> StartServer());
}
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><summary></span>
<span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> Stops the server and closes the form. Restart functionality omitted
</span><span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> for clarity.
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"></summary></span>
<span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">void</span> ButtonStop_Click(<span style="color: rgba(0, 0, 255, 1)">object</span><span style="color: rgba(0, 0, 0, 1)"> sender, RoutedEventArgs e)
{
SignalR.Dispose();
Close();
}
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><summary></span>
<span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> Starts the server and checks for error thrown when another server is already
</span><span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> running. This method is called asynchronously from Button_Start.
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"></summary></span>
<span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> StartServer()
{
</span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)">
{
SignalR </span>=<span style="color: rgba(0, 0, 0, 1)"> WebApp.Start(ServerURI);
}
</span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (TargetInvocationException)
{
WriteToConsole(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">A server is already running at </span><span style="color: rgba(128, 0, 0, 1)">"</span> +<span style="color: rgba(0, 0, 0, 1)"> ServerURI);
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.Dispatcher.Invoke(() => ButtonStart.IsEnabled = <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">;
}
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.Dispatcher.Invoke(() => ButtonStop.IsEnabled = <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">);
WriteToConsole(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Server started at </span><span style="color: rgba(128, 0, 0, 1)">"</span> +<span style="color: rgba(0, 0, 0, 1)"> ServerURI);
}
</span><span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)">This method adds a line to the RichTextBoxConsole control, using Dispatcher.Invoke if used
</span><span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> from a SignalR hub thread rather than the UI thread.</span>
<span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> WriteToConsole(String message)
{
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">(RichTextBoxConsole.CheckAccess()))
{
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.Dispatcher.Invoke(() =><span style="color: rgba(0, 0, 0, 1)">
WriteToConsole(message)
);
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">;
}
RichTextBoxConsole.AppendText(message </span>+ <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">\r</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
}
}
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><summary></span>
<span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> Used by OWIN's startup process.
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"></summary></span>
<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> Startup
{
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> Configuration(IAppBuilder app)
{
app.UseCors(CorsOptions.AllowAll);
app.MapSignalR();
}
}
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><summary></span>
<span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> Echoes messages sent using the Send message by calling the
</span><span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> addMessage method on the client. Also reports to the console
</span><span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> when clients connect and disconnect.
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"></summary></span>
<span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> MyHub : Hub
{
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> Send(<span style="color: rgba(0, 0, 255, 1)">string</span> name, <span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)"> message)
{
Clients.All.addMessage(name, message);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">Groups.Add</span>
}
public override Task OnConnected()
{
//Use Application.Current.Dispatcher to access UI thread from outside the MainWindow class
Application.Current.Dispatcher.Invoke(() =>
((MainWindow)Application.Current.MainWindow).WriteToConsole("Client connected: " + Context.ConnectionId));
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">base</span><span style="color: rgba(0, 0, 0, 1)">.OnConnected();
}
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">override</span> Task OnDisconnected(<span style="color: rgba(0, 0, 255, 1)">bool</span><span style="color: rgba(0, 0, 0, 1)"> ss)
{
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">Use Application.Current.Dispatcher to access UI thread from outside the MainWindow class</span>
Application.Current.Dispatcher.Invoke(() =><span style="color: rgba(0, 0, 0, 1)">
((MainWindow)Application.Current.MainWindow).WriteToConsole(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Client disconnected: </span><span style="color: rgba(128, 0, 0, 1)">"</span> +<span style="color: rgba(0, 0, 0, 1)"> Context.ConnectionId));
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">base</span><span style="color: rgba(0, 0, 0, 1)">.OnDisconnected(ss);
}
}
}
创建 WPF Client 端,新建一个 WPF 项目
安装 Nuget 包
替换 MainWindow 的前台 xmal 文件
<Window x:Name="WPFClient" x:Class="WPFClient.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="WPF SignalR Client" Height="552" Width="517" MinWidth="517" MinHeight="552" ResizeMode="CanMinimize" Closing="WPFClient_Closing"> <Grid> <StackPanel x:Name="SignInPanel" Margin="10,0" MaxWidth="550"> <Label Content="Enter user name:"/> <Grid> <TextBox x:Name="UserNameTextBox" Height="20" Margin="0,0,80,0"/> <Button x:Name="SignInButton" Content="Sign In" Width="75" Click="SignInButton_Click" HorizontalAlignment="Right"/> </Grid><span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">Label </span><span style="color: rgba(255, 0, 0, 1)">x:Name</span><span style="color: rgba(0, 0, 255, 1)">="StatusText"</span><span style="color: rgba(255, 0, 0, 1)"> Visibility</span><span style="color: rgba(0, 0, 255, 1)">="Collapsed"</span><span style="color: rgba(255, 0, 0, 1)"> HorizontalAlignment</span><span style="color: rgba(0, 0, 255, 1)">="Center"</span><span style="color: rgba(255, 0, 0, 1)"> Margin</span><span style="color: rgba(0, 0, 255, 1)">="0,10"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">StackPanel</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">StackPanel </span><span style="color: rgba(255, 0, 0, 1)">x:Name</span><span style="color: rgba(0, 0, 255, 1)">="ChatPanel"</span><span style="color: rgba(255, 0, 0, 1)"> Margin</span><span style="color: rgba(0, 0, 255, 1)">="10"</span><span style="color: rgba(255, 0, 0, 1)"> MaxWidth</span><span style="color: rgba(0, 0, 255, 1)">="550"</span><span style="color: rgba(255, 0, 0, 1)"> Visibility</span><span style="color: rgba(0, 0, 255, 1)">="Collapsed"</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">Grid</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">TextBox </span><span style="color: rgba(255, 0, 0, 1)">x:Name</span><span style="color: rgba(0, 0, 255, 1)">="TextBoxMessage"</span><span style="color: rgba(255, 0, 0, 1)"> Height</span><span style="color: rgba(0, 0, 255, 1)">="20"</span><span style="color: rgba(255, 0, 0, 1)"> TextWrapping</span><span style="color: rgba(0, 0, 255, 1)">="Wrap"</span><span style="color: rgba(255, 0, 0, 1)"> Margin</span><span style="color: rgba(0, 0, 255, 1)">="0,0,80,0"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">Button </span><span style="color: rgba(255, 0, 0, 1)">x:Name</span><span style="color: rgba(0, 0, 255, 1)">="ButtonSend"</span><span style="color: rgba(255, 0, 0, 1)"> Content</span><span style="color: rgba(0, 0, 255, 1)">="Send"</span><span style="color: rgba(255, 0, 0, 1)"> Width</span><span style="color: rgba(0, 0, 255, 1)">="75"</span><span style="color: rgba(255, 0, 0, 1)"> Height</span><span style="color: rgba(0, 0, 255, 1)">="20"</span><span style="color: rgba(255, 0, 0, 1)"> Click</span><span style="color: rgba(0, 0, 255, 1)">="ButtonSend_Click"</span><span style="color: rgba(255, 0, 0, 1)"> IsDefault</span><span style="color: rgba(0, 0, 255, 1)">="True"</span><span style="color: rgba(255, 0, 0, 1)"> IsEnabled</span><span style="color: rgba(0, 0, 255, 1)">="False"</span><span style="color: rgba(255, 0, 0, 1)"> HorizontalAlignment</span><span style="color: rgba(0, 0, 255, 1)">="Right"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">Grid</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">RichTextBox </span><span style="color: rgba(255, 0, 0, 1)">x:Name</span><span style="color: rgba(0, 0, 255, 1)">="RichTextBoxConsole"</span><span style="color: rgba(255, 0, 0, 1)"> HorizontalAlignment</span><span style="color: rgba(0, 0, 255, 1)">="Left"</span><span style="color: rgba(255, 0, 0, 1)"> Height</span><span style="color: rgba(0, 0, 255, 1)">="461"</span><span style="color: rgba(255, 0, 0, 1)"> ScrollViewer.VerticalScrollBarVisibility</span><span style="color: rgba(0, 0, 255, 1)">="Auto"</span><span style="color: rgba(255, 0, 0, 1)"> Margin</span><span style="color: rgba(0, 0, 255, 1)">="0,10"</span><span style="color: rgba(255, 0, 0, 1)"> IsReadOnly</span><span style="color: rgba(0, 0, 255, 1)">="True"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">StackPanel</span><span style="color: rgba(0, 0, 255, 1)">></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">Grid</span><span style="color: rgba(0, 0, 255, 1)">></span>
</Window>
替换后台代码
using System; using System.Net.Http; using System.Windows; using Microsoft.AspNet.SignalR.Client;
namespace WPFClient
{
/// <summary>
/// SignalR client hosted in a WPF application. The client
/// lets the user pick a user name, connect to the server asynchronously
/// to not block the UI thread, and send chat messages to all connected
/// clients whether they are hosted in WinForms, WPF, or a web application.
/// For simplicity, MVVM will not be used for this sample.
/// </summary>
public partial class MainWindow : Window
{
/// <summary>
/// This name is simply added to sent messages to identify the user; this
/// sample does not include authentication.
/// </summary>
public String UserName { get; set; }
public IHubProxy HubProxy { get; set; }
const string ServerURI = “http://localhost:8080/signalr”;
public HubConnection Connection { get; set; }
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> MainWindow()
{
InitializeComponent();
}
</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">void</span> ButtonSend_Click(<span style="color: rgba(0, 0, 255, 1)">object</span><span style="color: rgba(0, 0, 0, 1)"> sender, RoutedEventArgs e)
{
HubProxy.Invoke(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Send</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, UserName, TextBoxMessage.Text);
TextBoxMessage.Text </span>=<span style="color: rgba(0, 0, 0, 1)"> String.Empty;
TextBoxMessage.Focus();
}
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><summary></span>
<span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> Creates and connects the hub connection and hub proxy. This method
</span><span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> is called asynchronously from SignInButton_Click.
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"></summary></span>
<span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">async</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> ConnectAsync()
{
Connection </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> HubConnection(ServerURI);
Connection.Closed </span>+=<span style="color: rgba(0, 0, 0, 1)"> Connection_Closed;
HubProxy </span>= Connection.CreateHubProxy(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">MyHub</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">Handle incoming event from server: use Invoke to write to console from SignalR's thread</span>
HubProxy.On<<span style="color: rgba(0, 0, 255, 1)">string</span>, <span style="color: rgba(0, 0, 255, 1)">string</span>>(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">AddMessage</span><span style="color: rgba(128, 0, 0, 1)">"</span>, (name, message) =>
<span style="color: rgba(0, 0, 255, 1)">this</span>.Dispatcher.Invoke(() =><span style="color: rgba(0, 0, 0, 1)">
RichTextBoxConsole.AppendText(String.Format(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">{0}: {1}\r</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, name, message))
)
);
</span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)">
{
</span><span style="color: rgba(0, 0, 255, 1)">await</span><span style="color: rgba(0, 0, 0, 1)"> Connection.Start();
}
</span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (HttpRequestException)
{
StatusText.Content </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Unable to connect to server: Start server before connecting clients.</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">No connection: Don't enable Send button or show chat UI</span>
<span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">;
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">Show chat UI; hide login UI</span>
SignInPanel.Visibility =<span style="color: rgba(0, 0, 0, 1)"> Visibility.Collapsed;
ChatPanel.Visibility </span>=<span style="color: rgba(0, 0, 0, 1)"> Visibility.Visible;
ButtonSend.IsEnabled </span>= <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">;
TextBoxMessage.Focus();
RichTextBoxConsole.AppendText(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Connected to server at </span><span style="color: rgba(128, 0, 0, 1)">"</span> + ServerURI + <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">\r</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
}
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"><summary></span>
<span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> If the server is stopped, the connection will time out after 30 seconds (default), and the
</span><span style="color: rgba(128, 128, 128, 1)">///</span><span style="color: rgba(0, 128, 0, 1)"> Closed event will fire.
</span><span style="color: rgba(128, 128, 128, 1)">///</span> <span style="color: rgba(128, 128, 128, 1)"></summary></span>
<span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> Connection_Closed()
{
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">Hide chat UI; show login UI</span>
<span style="color: rgba(0, 0, 255, 1)">var</span> dispatcher =<span style="color: rgba(0, 0, 0, 1)"> Application.Current.Dispatcher;
dispatcher.Invoke(() </span>=> ChatPanel.Visibility =<span style="color: rgba(0, 0, 0, 1)"> Visibility.Collapsed);
dispatcher.Invoke(() </span>=> ButtonSend.IsEnabled = <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">);
dispatcher.Invoke(() </span>=> StatusText.Content = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">You have been disconnected.</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
dispatcher.Invoke(() </span>=> SignInPanel.Visibility =<span style="color: rgba(0, 0, 0, 1)"> Visibility.Visible);
}
</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">void</span> SignInButton_Click(<span style="color: rgba(0, 0, 255, 1)">object</span><span style="color: rgba(0, 0, 0, 1)"> sender, RoutedEventArgs e)
{
UserName </span>=<span style="color: rgba(0, 0, 0, 1)"> UserNameTextBox.Text;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">Connect to server (use async method to avoid blocking UI thread)</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">String.IsNullOrEmpty(UserName))
{
StatusText.Visibility </span>=<span style="color: rgba(0, 0, 0, 1)"> Visibility.Visible;
StatusText.Content </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Connecting to server...</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
ConnectAsync();
}
}
</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">void</span> WPFClient_Closing(<span style="color: rgba(0, 0, 255, 1)">object</span><span style="color: rgba(0, 0, 0, 1)"> sender, System.ComponentModel.CancelEventArgs e)
{
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (Connection != <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">)
{
Connection.Stop();
Connection.Dispose();
}
}
}
}
在解决方案的属性里面,设置 Server 和 Client 端一起启动
运行查看效果
源代码链接:
链接: http://pan.baidu.com/s/1eRC2qVw 密码: twh3