WPF System.InvalidOperationException:调用线程无法访问此对象,因为另一个线程拥有它

WPF System.InvalidOperationException:调用线程无法访问此对象,因为另一个线程拥有它,wpf,multithreading,Wpf,Multithreading,在我的Windows中,我有一个文本框,我喜欢从另一个线程更新文本属性。这样做时,我会得到InvalidOperationException,请参见标题。我在谷歌上找到了不同的链接来解释这一点,但我似乎仍然无法让它发挥作用 我试过的是: Window1代码: private static Window1 _myWindow; private MessageQueueTemplate _messageQueueTemplate; private const string LocalTemplate

在我的Windows中,我有一个文本框,我喜欢从另一个线程更新文本属性。这样做时,我会得到InvalidOperationException,请参见标题。我在谷歌上找到了不同的链接来解释这一点,但我似乎仍然无法让它发挥作用

我试过的是:

Window1代码:

private static Window1 _myWindow;
private MessageQueueTemplate _messageQueueTemplate;
private const string LocalTemplateName = "LocalExamSessionAccessCodeMessageQueueTemplate";
private const string RemoteTemplateName = "RemoteExamSessionAccessCodeMessageQueueTemplate";

...
public Window1()
{
    InitializeComponent();
    _myWindow = this;
}

public static Window1 MyWindow
{
    get
    {
        return _myWindow;
    }
}

public void LogText(string text)
{
    informationTextBox.Text += text + Environment.NewLine;
}
...
在另一个类中,实际上是在另一个线程中启动了一个spring.NET侦听器适配器,用于侦听某个队列

var thread = new Thread(
    new ThreadStart(
        delegate()
            {
                Window1.MyWindow.Dispatcher.Invoke(
                    System.Windows.Threading.DispatcherPriority.Normal,
                    new Action(
                        delegate()
                            {
                                Window1.MyWindow.LogText(text);
                            }
                        ));
            }
        ));
它不会引发错误,但Window1中LogText方法中的文本不会被触发,因此文本不会被更新

因此,基本上,我想从另一个线程中运行的另一个类更新这个TextBox组件。

好吧,使用Dispatcher.Invoke或BeginInvoke绝对是一种方法,但是除了创建线程之外,您还没有真正展示太多的代码-例如,您还没有在第二个代码块中启动线程

var thread = new Thread(
    new ThreadStart(
        delegate()
            {
                Window1.MyWindow.Dispatcher.Invoke(
                    System.Windows.Threading.DispatcherPriority.Normal,
                    new Action(
                        delegate()
                            {
                                Window1.MyWindow.LogText(text);
                            }
                        ));
            }
        ));

如果您将Dispatcher.Invoke代码放在先前获得InvalidOperationException的位置,则应该没有问题。

对于WPF,我发现以下构造:

 BackgroundWorker bw = new BackgroundWorker();
  bw.DoWork += ( s, e ) =>
  {
  };
  bw.RunWorkerCompleted += ( s, e ) =>
  {
  };
  bw.RunWorkerAsync();

是最有用的。RunWorkerCompleted块通常会更新一个ObservableCollection或触发一个RaisePropertyChange。

我很佩服你的耐心!我相信这是第无数次被问到!嗯,约翰,我知道是的,我已经搜索了其他问题,但没有找到我想要的答案。我可以去看许多关于调度员和线程的链接,但事实是我没有时间去看。我试着按照别人的建议去做,但没用@Jon Skeet:启动我的第二个代码块线程的代码在Spring.NET程序集中。它们创建侦听msmq队列并触发自定义适配器类中的方法的线程。在这门课上,我想更新一个文本框。@Lieven:如果你能创建一个简短但完整的程序来演示这个问题,那将非常非常有帮助。你可能会发现,通过这样做,你自己也会发现问题所在。完整的程序不需要处理Spring等,只需要创建一个线程,定期更新UI或类似的东西。这里的答案是使用Dispatcher,但我们无法判断您在显示的代码中犯了什么错误。好吧,就是这样,我不想要一个线程定期更新UI,我想要另一个线程直接访问UI组件。我无法控制此线程的启动方式。我想我的问题再清楚不过了。有一个UI组件Textbox和另一个线程想要设置这个Textbox的文本值。
Window1.MyWindow.informationTextBox.Dispatcher.Invoke(
    DispatcherPriority.Normal,
    new Action(() => Window1.MyWindow.informationTextBox.Text += value));