1. 程式人生 > >WPF+SignalR實現用戶列表實時刷新

WPF+SignalR實現用戶列表實時刷新

editor article web 自定義 dispose del value erl cal

原文:WPF+SignalR實現用戶列表實時刷新

版權聲明:本文為博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/lordwish/article/details/51789884

在實時通信應用中,最常用也最基本的就是終端列表的實時刷新,也就是當客戶端上線或下線時,服務端都會向全體客戶端推送通知及新的在線客戶端列表。


客戶端類

    public partial class
ClientModel { public ClientModel() { } private string _client_name; private string _client_ip="192.168.1.1"; private string _connectionid; //計算機名 public string ClientName { set { _client_name = value; } get
{ return _client_name; } } //計算機IP public string ClientIP { set { _client_ip = value; } get { return _client_ip; } } //通信連接id public string ConnectionId { set { _connectionid = value; } get
{ return _connectionid; } } }

服務端

服務端創建

服務端創建請參考下面文章

[使用WPF創建SignalR服務端]

服務端方法

在MyHub類中添加服務端方法。對於客戶端上線建立連接,服務端方法有兩種,一種是重載Hub類的OnConnected方法,另一種是就是自定義的方法了。OnConnected方法在客戶端與服務端建立通信連接時會被立即調用,但我們很多時候是先建立連接等到用戶驗證後再登錄刷新在線終端列表,也就是說兩者的觸發時機不同,但基本原理是一致的。
首先定義一個變量來存儲在線終端信息:

public List<ClientModel> ClientList = new List<ClientModel>();

OnConnected方法

        public override Task OnConnected()
        {
            ClientModel client = new ClientModel
            {
                ClientName = GetName(),//獲取遠程計算機名
                ClientIP = GetIp(),//獲取遠程計算機IP
                ConnectionId=Context.ConnectionId
            };
            foreach (ClientModel m in ClientList)
            {
                if (m.ClientIp==client.ClientIp)
                {
                    ClientList.Remove(m);
                    break;
                }
            }
            ClientList.Add(client);
            Clients.All.getclientlist(ClientList);
            string output = string.Format("用戶 {0} 上線,IP:{1}", client.ClientName, client.ClientIP);
            Application.Current.Dispatcher.Invoke(() =>
            {
                ((MainWindow)Application.Current.MainWindow).WriteToConsole(output);
            });
            return base.OnConnected();
        }

自定義方法GetClientList

public Task GetClientList(string clientname,string clientmac,string clientip)
        {
            ClientModel client = new ClientModel
            {
                ClientName = clientname,
                ClientIP = clientip,
                ConnectionId=Context.ConnectionId
            };
            foreach (Model.ClientModel m in ClientList)
            {
                if (m.ClientIp==clientip)
                {
                    ClientList.Remove(m);
                    break;
                }
            }
            ClientList.Add(client);
            Task all = Clients.All.getclientlist(ClientList);
            string output = string.Format("用戶 {0} 上線,IP:{1}", client.ClientName, client.ClientIP);
            Application.Current.Dispatcher.Invoke(() =>
            {
                ((MainWindow)Application.Current.MainWindow).WriteToConsole(output);
            });
            return all;
        }

客戶端

創建WPF項目ClientApp(不低於.NET Framework 4.0),使用NuGet管理器引用SignalR程序包,只需要引用Microsoft.AspNet.SignalR.Client即可。使用設計器添加一個數據列表(DataGrid或ListView)用於綁定在線客戶端列表。

創建並啟動通信連接

    public static HubConnection Connection = new HubConnection(ConfigurationManager.AppSettings["ServiceUri"]);
    public static IHubProxy MyHub;

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            ConnectAsync();
        }

        private async void ConnectAsync()
        {
            MyHub = Connection.CreateHubProxy("MyHub");
            try
            {
                await Connection.Start();//建立連接
            }
            catch (Exception)
            {
                throw;
            }
        }

針對服務端的實現方法,客戶端也有不同的方法,如果使用服務端的OnConnected方法,上面的方法足夠了,因為客戶端的基本信息都是包含在Context中的,客戶端與服務端建立連接時,服務端可以從Context中獲取客戶端信息。當然也可以寫個自定義方法連接服務端的GetClientList方法。

private void ClientOnline()
{
    string clientname=GetName();
    string clientip=GetIP();
    MyHub.Invoke("",clientname,clientip);
}

在通信連接建立後或在用戶執行相應操作後執行此方法,向服務端發送客戶端信息,服務端經過處理後將更改後的在線客戶端列表廣播至各客戶端,現在缺少的就是客戶端監聽服務端的方法了。監聽方法本質是一個長輪詢,可以在其中接受服務端推送的數據並執行相應操作。

public MainWindow()
{
     InitializeComponent();
     ConnectAsync();
     ConnectListener();
}
public void ConnectListener()
{
    MyHub.On<List<ClientModel>>("getclientlist", list =>{
        //數據綁定
        this.Dispatcher.Invoke(delegate{
            dgList.ItemsSource = list;
})
    });
}

最後就需要關閉終端下線的方法了
服務端:

        public override Task OnDisconnected(bool stopCalled)
        {
            Model.ClientModel client = new Model.ClientModel();
            foreach (Model.ClientModel m in ClientList)
            {
                if (m.ConnectionId==Context.ConnectionId)
                {
                    client = m;
                    ClientList.Remove(m);
                    break;
                }
            }
            Clients.All.getuserlist(ClientList);
            string output = string.Format("用戶 {0} 下線,IP:{1}", client.ClientName, client.ClientIP);
            Application.Current.Dispatcher.Invoke(() =>
            {
                ((MainWindow)Application.Current.MainWindow).WriteToConsole(output);
            });
            return base.OnDisconnected(stopCalled);
        }

客戶端

        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            Connection.Stop();
            Connection.Dispose();
        }

其實上面只是簡單的示例,而實際的業務場景會更復雜,但其基本原理是一致的,多多思考,可以擴展更多。

WPF+SignalR實現用戶列表實時刷新