利用SignalR來同步更新Winfrom

以前寫了個用Socket來更新多個Winfrom的試例,這兩天看了下SignalR,也用這個來試一下git

SignalR 地址:https://www.asp.net/signalrgithub

我這個也是基於 https://code.msdn.microsoft.com/Using-SignalR-in-WinForms-f1ec847b 改的數據庫

有不少地方基本上不明白,如今也只處在稍微會用的一些階段跨域

話很少講,先看代碼服務器

1.建立服務端app

樣子,基本上就這樣,先貼代碼asp.net

 

裏面有兩個類文件要注意 MyHub和Startupasync

using System.Threading.Tasks;
using Microsoft.AspNet.SignalR;
 
namespace ServerFrm
{
    public class MyHub:Hub
    {
        /// <summary>
        /// 在鏈接上時
        /// </summary>
        /// <returns></returns>
        public override Task OnConnected ()
        {
            ///向服務端寫入一些數據
            Program.serverFrm.WriteToInfo ("客戶端鏈接ID:" + Context.ConnectionId);
            return base.OnConnected ();
        }
 
        public override Task OnDisconnected (bool stopCalled)
        {
            ///向服務端寫入一些數據
            Program.serverFrm.WriteToInfo ("客戶端退出ID:" + Context.ConnectionId);
            return base.OnReconnected ();
        }
 
        /// <summary>
        /// 這是給客戶來調用的
        /// 當客戶端的添加按鈕點擊後
        /// 就調用此方法
        /// 當在客戶端綁定了下面的Update方法後
        /// 會自動去調用Update方法
        /// </summary>
        /// <param name="actionId">操做標識符</param>
        public void Send(string actionId)
        {
            /// 這是給客戶端來調用的
            /// 在鏈接服務器以前就給鏈接代理綁定這個方法
            /// 在客戶端鏈接上此服務後
            /// 客戶端綁定此方法,而且傳入一個標識符,本例爲 "1"(表明要更新界面上的datagridview
            Clients.All.Update (actionId);
        }
    }
}

在MyHub裏就只有一個方法是給客戶端調用的Sendide

等會就會在客戶端裏看到這個方法的調用場景ui

using Microsoft.Owin;
using Owin;
 
[assembly: OwinStartup (typeof (ServerFrm.Startup))]
 
namespace ServerFrm
{
    public class Startup
    {
        public void Configuration (IAppBuilder app)
        {
            // 有關如何配置應用程序的詳細信息,請訪問 http://go.microsoft.com/fwlink/?LinkID=316888
            //設置能夠跨域訪問
            app.UseCors (Microsoft.Owin.Cors.CorsOptions.AllowAll);
            //映射到默認的管理
            app.MapSignalR ();
        }
    }
}

Startup類,基本上我也弄不太明白,反正就這麼寫也不出錯,但不寫確定是錯<br><br>接着是服務端主要的代碼

using System;
using System.Windows.Forms;
 
namespace ServerFrm
{
    static class Program
    {
        /// <summary>
        /// 建立一個靜態的對象,方便給服務端調用
        /// </summary>
        internal static ServerFrm serverFrm { get; set; }
        /// <summary>
        /// 應用程序的主入口點。
        /// </summary>
        [STAThread]
        static void Main ()
        {
            Application.EnableVisualStyles ();
            Application.SetCompatibleTextRenderingDefault (false);
            serverFrm = new ServerFrm ();
            Application.Run (serverFrm);
        }
    }
}
using System;
using System.Threading.Tasks;
using System.Windows.Forms;
using Microsoft.Owin.Hosting;
 
namespace ServerFrm
{
    public partial class ServerFrm : Form
    {
        public ServerFrm ()
        {
            InitializeComponent ();
        }
 
        private IDisposable signalR { get; set; }
        private string serverUrl { get; set; } = System.Configuration.ConfigurationManager.AppSettings["url"];
        private void btnStart_Click (object sender , EventArgs e)
        {
            WriteToInfo ("正在鏈接中....");
            btnStart.Enabled = false;
            Task.Run (() =>
            {
                ServerStart ();
            });
        }
 
        /// <summary>
        /// 開啓服務
        /// </summary>
        private void ServerStart ()
        {
            try
            {
                //開啓服務
                signalR = WebApp.Start (serverUrl);
            }
            catch (  Exception ex )
            {
                //服務失敗時的處理
                WriteToInfo ("服務開啓失敗,緣由:" + ex.Message);
                this.Invoke (new Action (() =>
                 {
                     btnStart.Enabled = true;
                 }));
                return;
            }
            //服務成功,繼續下一步
            this.Invoke (new Action (() =>
             {
                //啓用中止按鈕
                btnStop.Enabled = true;
             }));
            WriteToInfo ("服務開啓成功 : " + serverUrl);
        }
 
        /// <summary>
        /// 向服務容器寫入信息
        /// </summary>
        /// <param name="msg">信息</param>
        internal void WriteToInfo(string msg)
        {
            if ( richTextBox.InvokeRequired )
            {
                this.Invoke (new Action (() =>
                  {
                      WriteToInfo (msg);
                  }));
                return;
            }
            richTextBox.AppendText (msg+Environment.NewLine);
        }
 
        private void btnStop_Click (object sender , EventArgs e)
        {
            if ( signalR!=null )
            {
                signalR.Dispose ();
            }
        }
 
        private void ServerFrm_FormClosing (object sender , FormClosingEventArgs e)
        {
            btnStop_Click (this , new EventArgs ());
            Close ();
        }
    }
}

服務端的代碼不多,主要的就是開啓服務而已

接着是客戶端

using System;
using System.Linq;
using System.Windows.Forms;
using Microsoft.AspNet.SignalR.Client;
using Model;
 
namespace ClinetFrm
{
    public partial class Clinet : Form
    {
        /// <summary>
        /// 鏈接代理對象
        /// </summary>
        private IHubProxy hubProxy { get; set; }
        /// <summary>
        /// 綁定的服務器url
        /// </summary>
        private string ServerURI = System.Configuration.ConfigurationManager.AppSettings["url"];
 
        /// <summary>
        /// 鏈接對象
        /// </summary>
        private HubConnection hubConnection { get; set; }
 
        public Clinet ()
        {
            InitializeComponent ();
        }
 
        private void Clinet_Load (object sender , EventArgs e)
        {
            InitData ();
            InitHub ();
        }
 
        private async void InitHub ()
        {
            //建立鏈接對象
            hubConnection = new HubConnection (ServerURI);
            //綁定一個集線器
            hubProxy = hubConnection.CreateHubProxy ("MyHub");
            //註冊服務端的方法,此方法請轉至服務端MyHub.cs中查看
            hubProxy.On ("Update" , (a) =>
            {
                //若是接收到的是"1"
                if ( a == "1" )
                {
                    //則更新界面
                    InitData ();
                }
            });
            try
            {
                //開始鏈接
                await hubConnection.Start ();
            }
            catch ( Exception ex )
            {
                this.Text = "服務器未鏈接上";
                return;
            }
            this.Text = "服務器已鏈接上";
        }
 
        /// <summary>
        /// 加載或更新datagridview
        /// </summary>
        private void InitData ()
        {
            //獲取數據
            DemoEntities demo = new DemoEntities ();
            var list = demo.DemoTable.ToList ();
            this.Invoke (new Action (() =>
             {
                 //綁定數據
                 dataGridView1.DataSource = list;
 
             }));
 
        }
 
        /// <summary>
        /// 添加按鈕
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnAdd_Click (object sender , EventArgs e)
        {
            DemoEntities demo = new DemoEntities ();
            demo.DemoTable.Add (new DemoTable ()
            {
                name = txtName.Text ,
                value = txtVal.Text
            });
            demo.SaveChanges ();
 
            ///使用代理啓動方法,啓動的是服務端中的Send方法
            ///而在服務端中Send會調用Update方法
            ///由於咱們在程序啓動時鏈接上了服務端
            ///並且綁定了Update方法,因此服務端在接收到Send方法被調用的通知時
            ///會自動去廣播全部已經連上服務端的客戶端使其調用Update方法
            hubProxy.Invoke ("Send" , "1");
        }
 
        private void Clinet_FormClosing (object sender , FormClosingEventArgs e)
        {
            if ( hubConnection != null )
            {
                hubConnection.Stop ();
                hubConnection.Dispose ();
            }
        }
    }
}

客戶端界面

再來張動圖演示一下

https://github.com/raozhihao/SignallR4WinformUpdateDemo

git地址

裏面用了EF數據庫,能夠照着Model - > DemoTable.cs 中的字段在數據庫中建一個

另外在git中加入了服務端向客戶端廣播的一些代碼

相關文章
相關標籤/搜索