zoukankan      html  css  js  c++  java
  • 【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 + "
    ");
            }
        }
        /// <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}
    ", 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 + "
    ");
            }
    
            /// <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

  • 相关阅读:
    LeetCode "Jump Game"
    LeetCode "Pow(x,n)"
    LeetCode "Reverse Linked List II"
    LeetCode "Unique Binary Search Trees II"
    LeetCode "Combination Sum II"
    LeetCode "Divide Two Integers"
    LeetCode "First Missing Positive"
    LeetCode "Clone Graph"
    LeetCode "Decode Ways"
    LeetCode "Combinations"
  • 原文地址:https://www.cnblogs.com/Soulless/p/7234352.html
Copyright © 2011-2022 走看看