一直以来都是做Web开发,虽然乱七八糟什么都接触一些,但几乎不怎么接触Winform, WPF这些,也很少接触多线程开发。
在公司有时候没有事儿做,但又不能随意上网浏览新闻什么的,会被IT监控,看多了总归不好。QQ也被禁用。大家用的都是OC。OC的聊天记录也会被上传到服务器。所以闲着的时候就开始决定做一个Winform的聊天室。初步包括 登陆,群聊,私聊,查看在线列表 这些基本功能。
今天遇到一个问题,上网查了一下,答案虽然正确,但让初步接触的我看的稀里糊涂的,大部分都是复制粘贴,甚至还出现了中文编程。。。所以自己也来记录一下。
背景:聊天室包括服务端和客户端,服务端点击“启动服务”按钮,将开启一个线程用来侦听连接服务器的客户端Socket,客户端连接后需要更新在线列表。因为 用户接入服务器 --> 将用户对象存入在线集合Dictionary<User,Socket>中 --> 更新在线列表 这个步骤是一气呵成的,所以都写在了侦听Socket的线程中,但起初我直接更新在线列表,会提示不能跨线程操作。
解决方案如下:
先声明一个委托,和一个委托变量,在进入线程前将更新在线列表的方法赋值给委托变量。
在进入线程后,查询控件的 InvokeRequired属性,若为True,则调用Invoke方法激活该委托方法。
public partial class MainForm : Form
{
......
private Dictionary<string, Socket> _clientList;
......
public delegate void UpdateOnlineList();
UpdateOnlineList updateOnlineList;
private void btn_StartService_Click(object sender, EventArgs e)
{
updateOnlineList = new UpdateOnlineList(OnOnlineListChange);
......
var listenThread = new Thread(StartListen);
listenThread.IsBackground = true;
listenThread.Start();
......
}
public void OnOnlineListChange()
{
listView_OnlineList.Items.Clear();
foreach (var item in _clientList)
{
listView_OnlineList.Items.Add(item.Key);
}
}
public void StartListen()
{
try
{
while (_isListening)
{
...
if (len > 0)
{
...
if (listView_OnlineList.InvokeRequired)
listView_OnlineList.Invoke(updateOnlineList);
...
}
}
}
}
}
Winform跨线程操作GUI