WPF 依赖项对象调用线程异常
本文关键字:线程 异常 调用 对象 依赖 WPF | 更新日期: 2023-09-27 18:31:48
我有以下代码,它创建一个临时文件夹并使用文件系统观察器轮询添加到位置属性上的文件夹的文件,并将它们添加到列表中:Pastebin 上的暂存盘.cs。这个想法是创建一个暂存盘对象,并让 FFmpeg 将视频帧提取到其中,FileSystemWatcher 在 FFmpeg 创建这些文件时构建这些文件的列表,并且该列表显示为我的 UI 绑定到的依赖对象。
我像这样绑定到暂存盘对象:
<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); }
我想我需要一个调度程序,在某处调用,但我不知道在哪里,我不知道第二个线程在哪里创建。我假设它与文件系统观察器写入文件列表有关。
有什么帮助吗?
谢谢!
我访问它的方式是这样的。它获取 UI 线程的调度程序
System.Windows.Application.Current.Dispatcher.Invoke(
(Action)(() =>
{
//Access the UI from here
}));
在我所拥有的内容和您在评论中列出的内容之间,这里要注意的主要事情是,无论您是否在后面的代码、视图模型、服务类中,无论您在何处,我的都将起作用。并非所有项目都有Dispatcher
,因此this.Dispatcher
并不总是有效。
尽管这是一个相当古老的线程,但我想给任何遇到我同样事情的人一个提示。这是一个故意冗长的描述,以便搜索引擎可以为下一个遇到这种晦涩行为的人/女孩找到它。
在收到此处所述的 SetValue/GetValue 编译错误后,我需要从依赖项对象派生我的 VM。
我想继续从我们的 ViewModelBase 派生我的 VM,它派生自我们的 AbstractNotifyPropertyChanged 类(当然,不能从 C# 中的 2 个完整类派生)。作为一个超级聪明的人,我想我会将DependencyObject派生添加到我的AbstractNotifyPropertyChanged类中。我看不出任何理由为什么这个小小的变化会产生任何不利影响。几个星期以来,应用程序运行良好。
总有一个毛茸茸的"然而"。在测试过程中,发现我的一个组合框在选择项目时使整个应用程序崩溃。这是由于未处理的无效操作异常。"调用线程无法访问此对象,因为其他线程拥有它。"使这个组合框与众不同的唯一原因是它对某些值使用了 DependencyProperty。
四天令人沮丧的调试无济于事,因为我的代码都没有进行调用。这一切都来自WPF,当调用堆栈到达GetValue中的VerifyAccess时,它就爆炸了。显然,当它被框架调用时,尝试调用Invoke跨线程不会发生吗?你会把调用放在哪里?
由于正常调试失败,我不得不以艰难的方式进行调试。我回溯了我的签入步骤以查找代码上次工作的时间。我已经知道它与组合框的 DependencyProperty 有某种关系,所以看到代码的变化,我的怀疑指向 DependencyObject 派生。
在对代码派生进行一些微调以从我的所有 ViewModels 的链中删除 DependencyObject(通过 ViewModelBase)并将该派生仅放置在我需要它的确切位置之后,问题已经解决。
您可以将调用包装在从调度程序调用的 Action() 中,如下所示:
this.Dispatcher.BeginInvoke(new Action(() =>
{
// your code accessing UI elements here
}));