WPF DependencyObject调用线程异常

时间:2014-11-23 16:33:44

标签: c# wpf multithreading filesystemwatcher invalidoperationexception

我有以下代码创建一个临时文件夹,并使用FileSystemWatcher轮询添加到Location属性上的文件夹的文件,并将它们添加到列表中:Scratchdisk.cs on Pastebin。我们的想法是创建一个Scratchdisk对象,并让FFmpeg将视频帧提取到其中,FileSystemWatcher在FFmpeg创建它们时构建这些文件的列表,该列表显示为我的UI绑定的DependencyObject。

我像这样绑定Scratchdisk对象:

<ItemsControl ItemsSource="{Binding Source=ThumbnailScratchdisk, Path=FileList}">
...
</ItemsControl>

在实际创建对象时,我得到以下异常:

A first chance exception of type 'System.InvalidOperationException' occurred in WindowsBase.dll

Additional information: The calling thread cannot access this object because a different thread owns it.

第28行get { return (List<string>)GetValue(FileListProperty); }

我想我需要一个Dispatcher.Invoke,但我不知道在哪里,我不知道第二个线程的创建位置。我假设它与FileSystemWatcher写入文件列表有关。

任何帮助?

谢谢!

3 个答案:

答案 0 :(得分:1)

我访问它的方式是这样的。它获取UI线程的调度程序

System.Windows.Application.Current.Dispatcher.Invoke(
  (Action)(() => 
  {
      //Access the UI from here 
  }));

在我所拥有的内容和你在评论中列出的内容之间要注意的主要事情是,无论你是在后面的代码,视图模型,服务类,无论在哪里,我都会工作。并非所有项目都有Dispatcher,因此this.Dispatcher并不总是有效。

答案 1 :(得分:-1)

您可以将调用包装在从Dispatcher调用的Action()中,如下所示:

this.Dispatcher.BeginInvoke(new Action(() =>
{
    // your code accessing UI elements here
}));

答案 2 :(得分:-1)

即使这是一个相当老的话题,我也想给遇到我同样事情的人一个提示。这是一个故意的冗长描述,因此搜索引擎可以为遇到这种晦涩行为的下一个家伙/女孩找到它。

在收到here描述的SetValue / GetValue编译错误后,我需要从DependencyObject派生我的VM。

我想继续从ViewModelBase派生我的VM,该ViewModelBase是从AbstractNotifyPropertyChanged类派生的(当然,不能从C#中的2个完整类派生)。作为超级聪明的人,我认为我将DependencyObject派生添加到AbstractNotifyPropertyChanged类中。我看不出有什么理由为什么这个小小的变化会产生不利的影响。数周以来,该应用程序运行良好。

总是有一个大毛茸茸的“但是”。在测试过程中,发现选择一个项目时,我的一个组合框使整个应用程序崩溃了。这是由于未处理的InvalidOperationException。 “调用线程无法访问该对象,因为其他线程拥有它。”唯一使此组合框与众不同的是,它对某些值使用了DependencyProperty。

四天令人沮丧的调试无济于事,因为我的代码都没有打电话。它们全部来自WPF,并且在调用栈在VerifyAccess中到达GetValue时爆炸。显然,当框架调用它时,尝试调用Invoke来跨线程不会发生吗?您将调用调用放在哪里?

由于正常调试失败,因此我不得不采取艰难的方法。我回溯了检入步骤,以查找代码上次工作的时间。我已经知道它与组合框的DependencyProperty有某种联系,因此,看到代码发生变化,我怀疑是DependencyObject派生的。

在对代码派生进行了一些细化之后,从我所有的ViewModel的链中删除了DependencyObject(通过ViewModelBase),并将该派生仅放置在我需要的确切位置上,问题已解决。