我正在运行一个基于对话框的程序,它定期发送 TCP,但也侦听 UDP 消息并将内容显示到 GUI。使用我最初使用的简单示例,一旦我开始在 while(true) 中监听,所有其他 GUI 功能都被关闭。然后我尝试生成一个线程来进行监听,但这些示例要求我创建一个新类,该类将 GUI 元素从我的视图中隐藏起来。
所以我的问题是,在不阻塞 GUI 线程的情况下侦听 UDP 消息并将内容写入 GUI 的最佳做法是什么?
我正在运行一个基于对话框的程序,它定期发送 TCP,但也侦听 UDP 消息并将内容显示到 GUI。使用我最初使用的简单示例,一旦我开始在 while(true) 中监听,所有其他 GUI 功能都被关闭。然后我尝试生成一个线程来进行监听,但这些示例要求我创建一个新类,该类将 GUI 元素从我的视图中隐藏起来。
所以我的问题是,在不阻塞 GUI 线程的情况下侦听 UDP 消息并将内容写入 GUI 的最佳做法是什么?
您需要让代码在某种后台线程中进行监听。这很简单,有很多方法可以将后台线程串起来,从Thread
类, BackgroundWorker
, Task
, ThreadPool.QueueUserWorkItem
(尽管在你的情况下线程池线程不合适,你需要一个完整的线程,因为你的操作是长时间运行的)等等。
之后,您只需要某种方式来更新 UI。同样,有几种方法可以这样做(一些特定于您正在使用的 UI 功能(WPF、winform 等),而另一些则不是。
使用IProgress<T>
特别有用,尤其是因为它不依赖于特定的 UI 技术。在 UI 中创建Progress
对象,并指定当您有特定结果时如何更新 UI,将对象传递给后台工作人员,并Report
在收到信息时让其进行。
一个示例可能如下所示:
private void Form1_Load(object sender, EventArgs e)
{
Progress<string> progress = new Progress<string>();
progress.ProgressChanged += data =>
{
textBox1.AppendText(data);
};
Thread tcpListener = new Thread(() => ListenForData(progress));
tcpListener.Start();
}
private void ListenForData(IProgress<string> progress)
{
while (true)
{
Thread.Sleep(1000);//placeholder for real IO to get data
progress.Report("data");
}
}
如果您没有 C# 4.5,则创建自己的Progress
类非常简单:
public interface IProgress<T>
{
void Report(T data);
}
public class Progress<T> : IProgress<T>
{
SynchronizationContext context;
public Progress()
{
context = SynchronizationContext.Current
?? new SynchronizationContext();
}
public Progress(Action<T> action)
: this()
{
ProgressReported += action;
}
public event Action<T> ProgressReported;
void IProgress<T>.Report(T data)
{
var action = ProgressReported;
if (action != null)
{
context.Post(arg => action((T)arg), data);
}
}
}