C# 无法使用DependencyObject,该对象属于与其父Freezable-prism不同的线程

C# 无法使用DependencyObject,该对象属于与其父Freezable-prism不同的线程,c#,wpf,multithreading,prism,sta,C#,Wpf,Multithreading,Prism,Sta,我在开发WPF应用程序时遇到了一个问题。 该应用程序基于Prism。 应用程序使用prism引导器和 在加载任何窗口之前,应用程序会在不同的线程(STA)上打开一个模式对话框, 然后加载一堆东西(服务等) 该对话框在此期间打开,允许向用户通知应用程序启动过程的进度(使用事件聚合器传递更新)。 加载完成后,bootstraper关闭对话框并打开主应用程序窗口。 到现在为止,一直都还不错。。。 然后,当关闭应用程序时,同样的事情也在发生。 关闭主窗口,打开对话框(再次在新STA线程上),以允许通知。

我在开发WPF应用程序时遇到了一个问题。 该应用程序基于Prism。 应用程序使用prism引导器和 在加载任何窗口之前,应用程序会在不同的线程(STA)上打开一个模式对话框, 然后加载一堆东西(服务等) 该对话框在此期间打开,允许向用户通知应用程序启动过程的进度(使用事件聚合器传递更新)。 加载完成后,bootstraper关闭对话框并打开主应用程序窗口。 到现在为止,一直都还不错。。。 然后,当关闭应用程序时,同样的事情也在发生。 关闭主窗口,打开对话框(再次在新STA线程上),以允许通知。 但是现在,当点击ShowDialog调用(发生在新STA线程中)时, 提出了一个例外情况: “不能使用属于与其父Freezable不同线程的DependencyObject”。 经过长时间的调试,我发现异常的原因是窗口的背景,它是从应用程序级别的合并字典(在wpf UI线程上实例化)中获取的画笔/图像。 如果在没有资源字典的情况下加载图像-一切都很顺利


总结: 只有在使用resourceDictionary时,并且只有在第二次调用新的STA线程时才会观察到异常,而新的STA线程反过来会加载一个对话框,并在调用ShowDialog时引发异常 如果只有一个对话框(例如,启动时没有对话框,关闭过程中只有对话框),则不会发生异常


我的问题是:原因是什么?在这种情况下,这种例外情况究竟意味着什么? (我知道通常会有一些来自其他线程的UI线程更新,但我不明白为什么这只发生在dialgo+线程的第二个实例上)


谢谢:)

我对此也有类似的问题。我不确定你是如何实现后台的。我可以试着解释一下我的情况,也许你能从中得到些什么。我创建了自己的基础窗口,我们称之为MyWindow,它继承自Windows。即

public class MyWindow : Window
{
}
我要做的是从应用程序资源字典的动态资源中应用背景

我首先选择了这个答案

public class MyWindow : Window
    {
        public MyWindow()
        {
            this.SetResourceReference(BackgroundProperty, "MyResourceKey");
        }
    }
当资源是一个固定颜色的ie时,这对我来说很有效

<SolidColorBrush x:Key="MyResourceKey" Color="White"/>
现在您有了对象,但它需要是一个依赖对象。我还没试过,但你也许能做到

DependencyObject temp = (DependencyObjet)this.TryFindResource("MyResourceKey"); 
现在您有了依赖项对象!这就是导致可自由释放父线程问题的原因。现在我们调用这个对象上的调度程序。我最终得到了这样的结果。这对我很管用,但我可能会尝试清理一下

public class MyWindow: Window
    {
        public MyWindow()
        {
            SetResources();                
        }

        private void SetResources()
        {
            DependencyObject dependencyObject;
            object temp;

                temp = this.TryFindResource("MyResourceKey");

                if (temp != null)
                {
                    if (temp is DependencyObject)
                    {
                        dependencyObject = (DependencyObject)temp;
                        if (!dependencyObject.CheckAccess())
                        {
                            dependencyObject.Dispatcher.BeginInvoke(new System.Action(() => { this.SetResources(); }));
                        }
                        else
                        {
                            this.SetValue(BackgroundProperty, temp);                            
                        }
                    }                   
                }
          }                  
    }
现在,这只是设置背景属性。我相信这对一种风格来说应该是一样的。所以你可以

this.SetValue(StyleProperty, temp)

花了一点时间才弄明白。但一旦我开始工作,我就兴奋不已。我们的资源使用的依赖项对象似乎遇到了线程问题,因此它是第一次加载,而不是第二次加载。第一次它在正确的线程上,但是在一路上的某个地方另一个线程被触发。还没弄明白这一点。如果有人对此有更好的解决方案,我很乐意看到

正如您正确提到的,您的背景对象是在主UI线程上创建的。您的背景实际上是一个笔刷对象,而笔刷是一个从属对象

创建DependencyObject时,它“依赖”于创建它的STA线程。因此,与其他依赖项对象一样,它只能在自己的线程上使用。这意味着STA和旧COM对象模型的某种兼容性

因此,当您尝试在另一个STA线程上使用它时,您会得到一个适当的异常


p.S对于被定义为资源的图像,我也有同样的问题。

因此,在删除第一个对话框时,仍然会发生这种情况(关闭对话框仍然不拥有资源)。
public class MyWindow: Window
    {
        public MyWindow()
        {
            SetResources();                
        }

        private void SetResources()
        {
            DependencyObject dependencyObject;
            object temp;

                temp = this.TryFindResource("MyResourceKey");

                if (temp != null)
                {
                    if (temp is DependencyObject)
                    {
                        dependencyObject = (DependencyObject)temp;
                        if (!dependencyObject.CheckAccess())
                        {
                            dependencyObject.Dispatcher.BeginInvoke(new System.Action(() => { this.SetResources(); }));
                        }
                        else
                        {
                            this.SetValue(BackgroundProperty, temp);                            
                        }
                    }                   
                }
          }                  
    }
this.SetValue(StyleProperty, temp)