富客户端 wpf, Winform 多线程更新UI控件

Posted JulyLuo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了富客户端 wpf, Winform 多线程更新UI控件相关的知识,希望对你有一定的参考价值。

前言  

在富客户端的app中,如果在主线程中运行一些长时间的任务,那么应用程序的UI就不能正常相应。因为主线程要负责消息循环,相应鼠标等事件还有展现UI。

因此我们可以开启一个线程来格外处理需要长时间的任务,但在富客户端中只有主线程才能更新UI的控件。

解决方法

简单的来说,我们需要从其他的线程来更新UI线程的控件,需要将这个操作转交给UI线程(线程marshal)。

方法1:

在底层的操作中,可以有以下的方法:

  • WPF中,在element的Dispatcher类中调用BeginInvoke或者Invoke方法
  • Metro中,在Dispatcher类中调用RunAsync或者Invoke方法
  • Winform中,在控件中直接调用BeginInvoke或者Invoke方法

以上所有的方法的参数都是一个Delegate,用此Delegate来代表需要处理的任务:

public IAsyncResult BeginInvoke(Delegate method);

BeginInvoke/RunAsync方法是将这个 Delegate推送到UI线程的消息队列中,这个消息队列也就是前面提到的鼠标,键盘事件等队列。

Invoke方法也是推送delegate到消息队列,但还会一直阻塞到此delegate被UI线程处理为止。所以一般来说我们还是用BeginInvoke/RunAsync方法。

对应app来说,我们可以将其想象为一下的伪代码:

while (!thisApplication.Ended)
{
wait for something to appear in message queue
Got something: what kind of message is it?
Keyboard/mouse message -> fire an event handler
User BeginInvoke message -> execute delegate
User Invoke message -> execute delegate & post result
}

那接下来我们用winform来demo一下:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        new Thread(work).Start();
    }

    void work()
    {
        Thread.Sleep(5000);
        UpdateMessage("july Luo thread Test");
    }

    void UpdateMessage(string message)
    {
        Action action = () => lblJulyLuo.Text = message;
        this.BeginInvoke(action);
    }
}

方法2

在 System.ComponentModel命名空间中,有 SynchronizationContext抽象类,此类也可以处理线程marshal。

在wpf,metro, winform中都定义了此类的子类,而且可以用SynchronizationContext.Current获取,然后调用Post方法,可以理解为将其他线程的任务post到UI线程中。

一下为demo:

public partial class Form1 : Form
{
    SynchronizationContext _uiSyncContext;

    public Form1()
    {
        InitializeComponent();
        _uiSyncContext = SynchronizationContext.Current;
    }

    void work()
    {
        Thread.Sleep(5000);
        UpdateMessage("july Luo thread Test");
    }

    void UpdateMessage(string message)
    {
        _uiSyncContext.Post(_ => lblJulyLuo.Text = message, null);
    }
}

SynchronizationContext类还有一个Send方法,和我们上面提到的Invoke方法的作用一致。

当然了还有BackgroundWorker类,此类在内部用了SynchronizationContext,所以其也可在其他线程中更新UI线程。

总结

富客户端中UI线程一直会处理着消息循环,无论使用那种方法都是将其推送到消息队列中以便UI线程处理。

 

以上是关于富客户端 wpf, Winform 多线程更新UI控件的主要内容,如果未能解决你的问题,请参考以下文章

winform与WPF有啥区别

winform和wpf里必知的多线程知识

wpf中 我新开一个线程添加控件到主窗体

C# winform 多线程更新数据,UI卡顿现象。

Winform和WPF的区别和WPF具体用法

C#关于winform线程更新form的文本框输出的问题