首先创建 WPF Server 端,新建一个 WPF 项目
安装 Nuget 包
替换 MainWindows 的Xaml代码
替换 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{ ////// 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. /// public partial class MainWindow : Window { public IDisposable SignalR { get; set; } const string ServerURI = "http://localhost:8080"; public MainWindow() { InitializeComponent(); } ////// Calls the StartServer method with Task.Run to not /// block the UI thread. /// private void ButtonStart_Click(object sender, RoutedEventArgs e) { WriteToConsole("Starting server..."); ButtonStart.IsEnabled = false; Task.Run(() => StartServer()); } ////// Stops the server and closes the form. Restart functionality omitted /// for clarity. /// private void ButtonStop_Click(object sender, RoutedEventArgs e) { SignalR.Dispose(); Close(); } ////// Starts the server and checks for error thrown when another server is already /// running. This method is called asynchronously from Button_Start. /// private void StartServer() { try { SignalR = WebApp.Start(ServerURI); } catch (TargetInvocationException) { WriteToConsole("A server is already running at " + ServerURI); this.Dispatcher.Invoke(() => ButtonStart.IsEnabled = true); return; } this.Dispatcher.Invoke(() => ButtonStop.IsEnabled = true); WriteToConsole("Server started at " + ServerURI); } ///This method adds a line to the RichTextBoxConsole control, using Dispatcher.Invoke if used /// from a SignalR hub thread rather than the UI thread. public void WriteToConsole(String message) { if (!(RichTextBoxConsole.CheckAccess())) { this.Dispatcher.Invoke(() => WriteToConsole(message) ); return; } RichTextBoxConsole.AppendText(message + "\r"); } } ////// Used by OWIN's startup process. /// class Startup { public void Configuration(IAppBuilder app) { app.UseCors(CorsOptions.AllowAll); app.MapSignalR(); } } ////// Echoes messages sent using the Send message by calling the /// addMessage method on the client. Also reports to the console /// when clients connect and disconnect. /// public class MyHub : Hub { public void Send(string name, string message) { Clients.All.addMessage(name, message); //Groups.Add } 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)); return base.OnConnected(); } public override Task OnDisconnected(bool ss) { //Use Application.Current.Dispatcher to access UI thread from outside the MainWindow class Application.Current.Dispatcher.Invoke(() => ((MainWindow)Application.Current.MainWindow).WriteToConsole("Client disconnected: " + Context.ConnectionId)); return base.OnDisconnected(ss); } }}
创建 WPF Client 端,新建一个 WPF 项目
安装 Nuget 包
替换 MainWindow 的前台 xmal 文件
替换后台代码
using System;using System.Net.Http;using System.Windows;using Microsoft.AspNet.SignalR.Client;namespace WPFClient{ ////// 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. /// public partial class MainWindow : Window { ////// This name is simply added to sent messages to identify the user; this /// sample does not include authentication. /// public String UserName { get; set; } public IHubProxy HubProxy { get; set; } const string ServerURI = "http://localhost:8080/signalr"; public HubConnection Connection { get; set; } public MainWindow() { InitializeComponent(); } private void ButtonSend_Click(object sender, RoutedEventArgs e) { HubProxy.Invoke("Send", UserName, TextBoxMessage.Text); TextBoxMessage.Text = String.Empty; TextBoxMessage.Focus(); } ////// Creates and connects the hub connection and hub proxy. This method /// is called asynchronously from SignInButton_Click. /// private async void ConnectAsync() { Connection = new HubConnection(ServerURI); Connection.Closed += Connection_Closed; HubProxy = Connection.CreateHubProxy("MyHub"); //Handle incoming event from server: use Invoke to write to console from SignalR's thread HubProxy.On("AddMessage", (name, message) => this.Dispatcher.Invoke(() => RichTextBoxConsole.AppendText(String.Format("{0}: {1}\r", name, message)) ) ); try { await Connection.Start(); } catch (HttpRequestException) { StatusText.Content = "Unable to connect to server: Start server before connecting clients."; //No connection: Don't enable Send button or show chat UI return; } //Show chat UI; hide login UI SignInPanel.Visibility = Visibility.Collapsed; ChatPanel.Visibility = Visibility.Visible; ButtonSend.IsEnabled = true; TextBoxMessage.Focus(); RichTextBoxConsole.AppendText("Connected to server at " + ServerURI + "\r"); } /// /// If the server is stopped, the connection will time out after 30 seconds (default), and the /// Closed event will fire. /// void Connection_Closed() { //Hide chat UI; show login UI var dispatcher = Application.Current.Dispatcher; dispatcher.Invoke(() => ChatPanel.Visibility = Visibility.Collapsed); dispatcher.Invoke(() => ButtonSend.IsEnabled = false); dispatcher.Invoke(() => StatusText.Content = "You have been disconnected."); dispatcher.Invoke(() => SignInPanel.Visibility = Visibility.Visible); } private void SignInButton_Click(object sender, RoutedEventArgs e) { UserName = UserNameTextBox.Text; //Connect to server (use async method to avoid blocking UI thread) if (!String.IsNullOrEmpty(UserName)) { StatusText.Visibility = Visibility.Visible; StatusText.Content = "Connecting to server..."; ConnectAsync(); } } private void WPFClient_Closing(object sender, System.ComponentModel.CancelEventArgs e) { if (Connection != null) { Connection.Stop(); Connection.Dispose(); } } }}
在解决方案的属性里面,设置 Server 和 Client 端一起启动
运行查看效果
源代码链接:
链接: 密码: twh3
分类: