Dispatcher.Invoke更新UI控件 [英] Dispatcher.Invoke to update UI Control
问题描述
我有一个.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 $ c $
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屋!