隐藏

利用SignalR来同步更新Winfrom小试

发布:2020/11/13 10:34:16作者:管理员 来源:本站 浏览次数:966

之前写了个用Socket来更新多个Winfrom的试例,这两天看了下SignalR,也用这个来试一下

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

我这个也是基于 https://code.msdn.microsoft.com/Using-SignalR-in-WinForms-f1ec847b 改的

有很多地方基本上不明白,现在也只处在稍微会用的一些阶段

话不多讲,先看代码

1.创建服务端

样子,基本上就这样,先贴代码

里面有两个类文件要注意 MyHub和Startup

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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里就只有一个方法是给客户端调用的Send

等会就会在客户端里看到这个方法的调用场景

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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 ();
        }
    }
}


1
Startup类,基本上我也弄不太明白,反正就这么写也不出错,但不写肯定是错<br><br>接着是服务端主要的代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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);
        }
    }
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
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 ();
        }
    }
}

服务端的代码很少,主要的就是开启服务而已

接着是客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
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中加入了服务端向客户端广播的一些代码