首先创建 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> <Button x:Name="ButtonStart" Content="Start" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="100" Click="ButtonStart_Click"/>
<Button x:Name="ButtonStop" Content="Stop" HorizontalAlignment="Left" Margin="225,10,0,0" VerticalAlignment="Top" Width="100" Click="ButtonStop_Click" IsEnabled="False"/>
<RichTextBox x:Name="RichTextBoxConsole" HorizontalAlignment="Left" Height="243" Margin="10,35,0,0" VerticalAlignment="Top" Width="315">
<FlowDocument>
<Paragraph>
</Paragraph>
</FlowDocument>
</RichTextBox> </Grid>
</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"; 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);
//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 文件

<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> <Label x:Name="StatusText" Visibility="Collapsed" HorizontalAlignment="Center" Margin="0,10"/>
</StackPanel>
<StackPanel x:Name="ChatPanel" Margin="10" MaxWidth="550" Visibility="Collapsed">
<Grid>
<TextBox x:Name="TextBoxMessage" Height="20" TextWrapping="Wrap" Margin="0,0,80,0"/>
<Button x:Name="ButtonSend" Content="Send" Width="75" Height="20" Click="ButtonSend_Click" IsDefault="True" IsEnabled="False" HorizontalAlignment="Right"/>
</Grid>
<RichTextBox x:Name="RichTextBoxConsole" HorizontalAlignment="Left" Height="461" ScrollViewer.VerticalScrollBarVisibility="Auto" Margin="0,10" IsReadOnly="True"/>
</StackPanel>
</Grid>
</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; } 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();
}
}
}
}

在解决方案的属性里面,设置 Server 和 Client 端一起启动

运行查看效果

源代码链接:

链接: http://pan.baidu.com/s/1eRC2qVw 密码: twh3

最新文章

  1. 关于Access restriction: The type &#39;Application&#39; is not API (restriction on required library)
  2. 分布式数据库Hbase
  3. 今天初步了解了informix的锁的概念
  4. C#委托理解(个人观点)
  5. 开发Protege插件时,出现打开Protege后并不显示插件的原因
  6. NGUI 滑动页(UIToggle和UIToggledObjects)
  7. Java集合之TreeMap
  8. Epic - Desirable Number
  9. (五)、nodejs使用bootstrap的样式进行分页
  10. hdu 1709 The Balance
  11. winForm 中子窗体关闭但不释放对象,方便下次继续打开
  12. Android Intent实现页面跳转
  13. HTML5进阶(三)HBuilder实现软件自动升级(优化篇)
  14. 一条SQL语句执行得很慢的原因有哪些?
  15. C++实现算法常用的STL---整理
  16. Nginx子域名配置
  17. SQLServer、MySQL、Oracle如何查看所有表的条数
  18. 使用Java函数接口及lambda表达式隔离和模拟外部依赖更容易滴单测
  19. 大数据之 Hadoop学习笔记
  20. Battery Historian之App耗电量测试

热门文章

  1. APUE-文件和目录(六)函数ftw和nftw
  2. html5shiv.min.js 和 respond.min.js 作用(bootstrap做IE低版本兼容时需要用到这两个插件)
  3. iOS开发之常用资讯类App的分类展示与编辑的完整案例实现(Swift版)
  4. EF之通过不同条件查找去重复
  5. Java集合源码分析之 LinkedList
  6. Scrapyd部署爬虫
  7. Scrapy爬虫大战京东商城
  8. PHPUnit-函数依赖-数据提供-异常-忽略-自动生成
  9. Jenkins插件开发
  10. java中String与StringBuffer拼接的区别