Dispatcher.Invoke更新UI控件 [英] Dispatcher.Invoke to update UI Control

查看:275
本文介绍了Dispatcher.Invoke更新UI控件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个.Net 4.0类,该类具有自定义事件处理程序( StatusChanged )。我正在尝试通过线程使用此类。我不喜欢使用 BackgroundWorker ,因为我使用的库不支持多线程单元状态。

I have a .Net 4.0 class that has a custom event handler (StatusChanged). I am trying to consume this class via a thread. I don't have the luxury of using BackgroundWorker because libraries I use do not support multi thread apartment state.

StatusChanged 委托中的参数之一是字符串。

One of the parameters in the StatusChanged delegate is a string.

在用户界面中,单击按钮即可初始化线程

In the UI, a button click initializes a thread that uses my class.

我正在尝试制作它,以便UI控件(WPF)被更新为 StatusChanged StatusChanged 事件触发时,c>字符串参数。我的理解是 Dispatcher.Invoke 可以做到这一点,但是我没有运气想出如何从中拉出字符串。

I am trying to make it so a UI control (WPF) gets updated to be the StatusChanged string parameter when StatusChanged event fires. My understanding is that Dispatcher.Invoke can do this, but I am not having any luck figuring out how to pull the string out of it.

本质上,我试图获得与 BackgroundWorker.ProgressChanged 等效的东西(与 ProgressChangedEventArgument.UserState )。

Essentially, I am trying to get the equivalent of BackgroundWorker.ProgressChanged (with the ProgressChangedEventArgument.UserState).

下面是一些缩小代码以演示我要得到的内容:

Here is some scaled-down code to demonstrate what I'm getting at:

带有事件处理程序的类:

Class with event handler:

public class MyClass
{
    public event EventHandler StatusChanged;

    private void alertStatus(string message)
    {
        if(StatusChanged == null)
            return;
        this.StatusChanged(message, new EventArgs());
    }

    public void DoStuff()
    {
        ///Do Stuff 1
        alertStatus("Done with stuff #1");

        ///Do Stuff 2            
        alertStatus("Done with stuff #2");
    }
}

因此,按钮的.Click事件将执行以下操作:

So a button's .Click event would do something like this:

private void buttonClicked(object sender, EventArgs e)
{
    Thread t = new Thread(doWork);
    t.Start();
}

private void doWork()
{
    MyClass class = new MyClass();
    class.StatusChanged += ...
    class.DoStuff();
    ///As StatusChanged fires within MyClass, a UI Textbox would get updated
}


推荐答案

使用lambda表达式最简单:

It's easiest just to use a lambda expression:

private void doWork()
{
    // Name changed to avoid it being a keyword
    MyClass clazz = new MyClass();
    clazz.StatusChanged += (sender, args) => {
        string message = (string) sender; // This is odd
        Action action = () => textBox.Text = message;
        Dispatcher.Invoke(action);
    };
    clazz.DoStuff();
}

使用字符串作为事件的发送者虽然很奇怪-否则最好使用 EventArgs 的子类,并使其存储消息-然后使事件使用 EventHandler< T> 而不只是 EventHandler

It's very odd using a string as the sender of an event though - it would be better to use a subclass of EventArgs, and make that store the message - then make your event use EventHandler<T> instead of just EventHandler.

上面的代码有点令人困惑,因为您使用一个订阅事件委托,然后将另一个传递给 Dispatcher.Invoke -因此是两个lambda表达式(一个在另一个内部)。您始终可以使用方法组,至少对于外部的方法组:

The above code is slightly confusing because you're subscribing to the event with one delegate, then passing another to Dispatcher.Invoke - hence the two lambda expressions (one inside another). You could always use a method group instead, at least for the outer one:

private void doWork()
{
    // Name changed to avoid it being a keyword
    MyClass clazz = new MyClass();
    clazz.StatusChanged += HandleStatusChange;
    clazz.DoStuff();
}

private void HandleStatusChange(object sender, EventArgs e)
{
    string message = (string) sender; // This is odd
    Action action = () => textBox.Text = message;
    Dispatcher.Invoke(action);
}

这篇关于Dispatcher.Invoke更新UI控件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆