.net 从WPF服务器向WPF客户端发送消息的信号器
我一直在研究一个示例,其中在自托管WPF服务器应用程序中使用Signalr2与WPF客户端通信。我已经下载了这个项目——我将在下面展示它——它运行得很好: WPF服务器:.net 从WPF服务器向WPF客户端发送消息的信号器,.net,signalr,.net,Signalr,我一直在研究一个示例,其中在自托管WPF服务器应用程序中使用Signalr2与WPF客户端通信。我已经下载了这个项目——我将在下面展示它——它运行得很好: WPF服务器: public partial class MainWindow : Window { public IDisposable SignalR { get; set; } const string ServerURI = "http://localhost:8080"; public MainWi
public partial class MainWindow : Window
{
public IDisposable SignalR { get; set; }
const string ServerURI = "http://localhost:8080";
public MainWindow()
{
InitializeComponent();
}
/// <summary>
/// Calls the StartServer method with Task.Run to not
/// block the UI thread.
/// </summary>
private void ButtonStart_Click(object sender, RoutedEventArgs e)
{
WriteToConsole("Starting server...");
ButtonStart.IsEnabled = false;
Task.Run(() => StartServer());
}
/// <summary>
/// Stops the server and closes the form. Restart functionality omitted
/// for clarity.
/// </summary>
private void ButtonStop_Click(object sender, RoutedEventArgs e)
{
SignalR.Dispose();
Close();
}
/// <summary>
/// Starts the server and checks for error thrown when another server is already
/// running. This method is called asynchronously from Button_Start.
/// </summary>
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");
}
}
/// <summary>
/// Used by OWIN's startup process.
/// </summary>
class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseCors(CorsOptions.AllowAll);
app.MapSignalR();
}
}
/// <summary>
/// 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.
/// </summary>
public class MyHub : Hub
{
public void Send(string name, string message)
{
Clients.All.addMessage(name, message);
}
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()
{
//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();
}
}
公共部分类主窗口:窗口
{
公共IDisposable信号器{get;set;}
常量字符串ServerURI=”http://localhost:8080";
公共主窗口()
{
初始化组件();
}
///
///使用Task.Run调用StartServer方法以不运行
///阻止UI线程。
///
私有无效按钮开始单击(对象发送者,路由目标)
{
WriteToConsole(“启动服务器…”);
ButtonStart.IsEnabled=false;
Task.Run(()=>StartServer());
}
///
///停止服务器并关闭表单。忽略重新启动功能
///为了清楚起见。
///
私有无效按钮停止单击(对象发送者,路由目标)
{
Dispose();
Close();
}
///
///启动服务器并检查在另一台服务器已启动时引发的错误
///正在运行。此方法从按钮开始异步调用。
///
私有void StartServer()
{
尝试
{
SignalR=WebApp.Start(ServerURI);
}
捕获(目标异常)
{
WriteToConsole(“服务器已在“+ServerURI”上运行);
this.Dispatcher.Invoke(()=>ButtonStart.IsEnabled=true);
回来
}
this.Dispatcher.Invoke(()=>ButtonStop.IsEnabled=true);
WriteToConsole(“服务器启动于”+ServerURI);
}
///此方法使用Dispatcher.Invoke(如果使用)向RichTextBoxConsole控件添加一行
///来自信号集线器线程而不是UI线程。
公共无效WriteToConsole(字符串消息)
{
如果(!(RichTextBoxConsole.CheckAccess())
{
this.Dispatcher.Invoke(()=>
WriteToConsole(消息)
);
回来
}
RichTextBoxConsole.AppendText(消息+“\r”);
}
}
///
///用于OWIN的启动过程。
///
类启动
{
公共无效配置(IAppBuilder应用程序)
{
应用程序UseCors(CorsOptions.AllowAll);
app.mapsigner();
}
}
///
///通过调用
///客户端上的addMessage方法。还向控制台报告
///当客户端连接和断开连接时。
///
公共类MyHub:Hub
{
公共无效发送(字符串名称、字符串消息)
{
Clients.All.addMessage(名称、消息);
}
已连接的公用覆盖任务()
{
//使用Application.Current.Dispatcher从MainWindow类外部访问UI线程
Application.Current.Dispatcher.Invoke(()=>
((MainWindow)Application.Current.MainWindow).WriteConsole(“连接的客户端:“+Context.ConnectionId”);
返回base.OnConnected();
}
公共覆盖任务OnDisconnected()
{
//使用Application.Current.Dispatcher从MainWindow类外部访问UI线程
Application.Current.Dispatcher.Invoke(()=>
((MainWindow)Application.Current.MainWindow).WriteConsole(“客户端断开连接:“+Context.ConnectionId”);
返回base.OnDisconnected();
}
}
以下是WPF客户端:
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; }
public MainWindow()
{
InitializeComponent();
}
private void ButtonSend_Click(object sender, RoutedEventArgs e)
{
HubProxy.Invoke("Send", UserName, TextBoxMessage.Text);
TextBoxMessage.Text = String.Empty;
TextBoxMessage.Focus();
}
/// <summary>
/// Creates and connects the hub connection and hub proxy. This method
/// is called asynchronously from SignInButton_Click.
/// </summary>
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<string, string>("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");
}
/// <summary>
/// If the server is stopped, the connection will time out after 30 seconds (default), and the
/// Closed event will fire.
/// </summary>
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();
}
}
}
公共部分类主窗口:窗口
{
///
///此名称仅添加到已发送的消息中以标识用户;此
///示例不包括身份验证。
///
公共字符串用户名{get;set;}
公共IHubProxy HubProxy{get;set;}
常量字符串ServerURI=”http://localhost:8080/signalr";
公共HUB连接{get;set;}
公共主窗口()
{
初始化组件();
}
私有无效按钮发送\单击(对象发送者,路由目标)
{
调用(“发送”,用户名,TextBoxMessage.Text);
TextBoxMessage.Text=String.Empty;
TextBoxMessage.Focus();
}
///
///创建并连接集线器连接和集线器代理。此方法
///从SignInButton\u Click异步调用。
///
私有异步void ConnectAsync()
{
连接=新的HUB连接(ServerURI);
连接关闭+=连接关闭;
HubProxy=Connection.CreateHubProxy(“MyHub”);
//处理来自服务器的传入事件:使用Invoke从信号器的线程写入控制台
HubProxy.On(“AddMessage”,(名称、消息)=>
this.Dispatcher.Invoke(()=>
RichTextBoxConsole.AppendText(String.Format(“{0}:{1}\r”,名称,消息))
)
);
尝试
{
等待连接。开始();
}
捕获(HttpRequestException)
{
StatusText.Content=“无法连接到服务器:在连接客户端之前启动服务器。”;
//无连接:不启用发送按钮或显示聊天界面
回来
}
//显示聊天界面;隐藏登录界面
SignInPanel.Visibility=可见性。已折叠;
ChatPanel.Visibility=Visibility.Visible;
ButtonSend.IsEnabled=true;
TextBoxMessage.Focus();
AppendText(“连接到服务器的“+ServerURI+”\r”);
}
///
///如果服务器停止,连接将在30秒后超时(默认),并且
///关闭的事件将被触发。
///
无效连接\u已关闭()
{
//隐藏聊天界面;显示登录界面
var dispatcher=Application.Current.dispatcher;
dispatcher.Invoke(()=>ChatPanel.Visibility=Visibility.Collapsed);
dispatcher.Invoke(()=>ButtonSend.IsEnabled=false);
dispatcher.Invoke(()=>StatusText.Content=“您已断开连接。”);
dispatcher.Invoke(()=>SignInPanel.Visibility=Visibility.Visi
HubProxy.On<string, string>("AddMessage", (name, message) =>
this.Dispatcher.Invoke(() =>
RichTextBoxConsole.AppendText(String.Format("{0}: {1}\r", name, message))
)
);