来自不同线程的火灾事件

在我的主窗口( 线程A )中,我启动一个新线程( 线程B ),它在用户等待时完成一些工作。

如果出现错误或用户需要额外信息,线程B将触发事件,线程A将侦听这些事件。

在线程A的事件监听器中,我需要向用户显示对话框消息,我有一个自定义对话框窗口并使用dialogWindow.showDialog()显示它。 这工作正常,但当我尝试设置对话框的所有者时会导致错误,我执行此对话窗口dialogWindow.Owner = Window.GetWindow(this)

我得到的错误是: 调用线程无法访问此对象,因为另一个线程拥有它。

侦听从不同线程触发的事件的正确方法是什么?

从后台线程向UI线程引发事件的正确方法是,应该在该Dispatcher上引发事件,这里的键是获取UIthread的调度程序。

UIDisaptcher.BeginInvoke((ThreadStart)(()=> RaiseEventToUIThread()));

当UI线程侦听raise事件时,它可以设置Owner属性(因为窗口是由UI线程创建的)。

事件侦听器代码将在触发事件的线程中隐式运行,因此事件侦听器不是线程绑定的。

如果您希望在事件处理过程中在UI中显示某些内容,则应自行进行编组。 像这样的东西:

 void OnEvent(object sender, EventArgs args) { // runs in the event sender's thread string x = ComputeChanges(args); Dispatcher.BeginInvoke((Action)( () => UpdateUI(x) )); } void UpdateUI(string x) { // runs in the UI thread control.Content = x; // - or - new DialogWindow() { Content = x, Owner = this }.ShowDialog(); // - or whatever } 

所以:你在后台线程中优先执行计算(如果有的话),而不触及UI; 之后,当您知道UI中需要进行哪些更改时,您将在UI线程中执行UI更新代码。

Dispatcher是控件的属性,因此如果您的代码是UI的一部分,您将免费获得Dispatcher。 否则,您可以从任何控件(例如, control.Dispatcher )中获取调度程序。

当然 – >我们要做的是使用SynchronizationContext。 因此,当您启动一个新线程时,您捕获(在UI线程上)当前上下文并将其作为参数传递给第二个线程。

然后在第二个线程上,当你想要提出一个事件时,你这样做:

  if (_uiThreadId != Thread.CurrentThread.ManagedThreadId) { _uiContext.Post( new SendOrPostCallback(delegate(object o) { OnYourEvent((EventArgs)o); }), e); } else OnYourEvent(e);