当前位置: 首页 > news >正文

【SignalR学习系列】5. SignalR WPF程序

首先创建 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

 
分类:  SignalR

相关文章:

  • 使用UAC白名单让指定的程序不受UAC限制
  • 无痕浏览的坑
  • 自动化执行 - 钉钉机器人通知
  • 想了解概率图模型?你要先理解图论的基本定义与形式
  • 从源码分析JSONObject因版本差异导致toString格式异常问题
  • 封装html代码块到js函数中
  • K8S集群tls证书管理
  • Android -- DragDrop
  • 一个完整Java Web项目背后的密码
  • PHP字符串操作(string替换、删除、截取、复制、连接、比较、查找、包含、大小写转换、切割成数组等)...
  • vue element ui excel json2csv csv 导出
  • 这7个不可错过的数据可视化技术,让你的位置信息跃然纸上
  • JAVA运维-Tomcat支持APR模式
  • 路由器密码忘了怎么办 自己动手不求人
  • 源码编译安装 PHP 7.1.5 + nginx 1.12.0
  • 【vuex入门系列02】mutation接收单个参数和多个参数
  • CentOS 7 防火墙操作
  • Java 多线程编程之:notify 和 wait 用法
  • Mac 鼠须管 Rime 输入法 安装五笔输入法 教程
  • Tornado学习笔记(1)
  • vue数据传递--我有特殊的实现技巧
  • weex踩坑之旅第一弹 ~ 搭建具有入口文件的weex脚手架
  • 编写符合Python风格的对象
  • 个人博客开发系列:评论功能之GitHub账号OAuth授权
  • 关于 Linux 进程的 UID、EUID、GID 和 EGID
  • 技术攻略】php设计模式(一):简介及创建型模式
  • 简单易用的leetcode开发测试工具(npm)
  • 开源SQL-on-Hadoop系统一览
  • 力扣(LeetCode)21
  • 每个JavaScript开发人员应阅读的书【1】 - JavaScript: The Good Parts
  • 前端技术周刊 2019-01-14:客户端存储
  • 一个JAVA程序员成长之路分享
  • ​二进制运算符:(与运算)、|(或运算)、~(取反运算)、^(异或运算)、位移运算符​
  • # C++之functional库用法整理
  • # 飞书APP集成平台-数字化落地
  • (1/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序
  • (BFS)hdoj2377-Bus Pass
  • (day6) 319. 灯泡开关
  • (html5)在移动端input输入搜索项后 输入法下面为什么不想百度那样出现前往? 而我的出现的是换行...
  • (PWM呼吸灯)合泰开发板HT66F2390-----点灯大师
  • (待修改)PyG安装步骤
  • (附源码)spring boot基于Java的电影院售票与管理系统毕业设计 011449
  • (附源码)ssm智慧社区管理系统 毕业设计 101635
  • (七)Knockout 创建自定义绑定
  • (四)Android布局类型(线性布局LinearLayout)
  • (一)80c52学习之旅-起始篇
  • (转)Mysql的优化设置
  • (转)Sublime Text3配置Lua运行环境
  • (轉貼) 資訊相關科系畢業的學生,未來會是什麼樣子?(Misc)
  • .NET 除了用 Task 之外,如何自己写一个可以 await 的对象?
  • .NET/C# 使用 #if 和 Conditional 特性来按条件编译代码的不同原理和适用场景
  • .NET国产化改造探索(一)、VMware安装银河麒麟
  • /使用匿名内部类来复写Handler当中的handlerMessage()方法
  • @data注解_SpringBoot 使用WebSocket打造在线聊天室(基于注解)
  • @test注解_Spring 自定义注解你了解过吗?