是否有一种方法可以隔离WPF中使用的资源?



我有一个设计不好的大型应用程序。特别是在启动时,它会初始化UI线程中的许多服务。问题是初始化可能很耗时,因此UI线程在此期间会冻结。我不能把它移到后台线程,因为有些服务依赖于它们启动的线程,而且有太多的代码要逐行检查它发生在哪里。

这个想法是显示加载屏幕与ProgressBar在单独的线程与单独的Dispatcher:

ThreadStart initLoadingDialog = () =>
                                    {
                                        _currentDispatcher = Dispatcher.CurrentDispatcher;
                                        _dialogWindow = new MyDialogWindow();
                                        _dialogWindow.Show();
                                        Dispatcher.Run();
                                    };
var thread = new Thread(initLoadingDialog);
thread.SetApartmentState(ApartmentState.STA);
thread.Start();

(好吧,代码是不完全精确,因为我使用MVVM,没有MyDialogWindowClass,而只是窗口的内容设置为ViewModel和DataTemplate资源。但这并不重要(在这里)。

它工作,但似乎使用一些资源,从而有效地将它们绑定到非主ui线程。后来我收到异常"无法将属性'Background'中的值转换为类型'System.Windows.Media.Brush'的对象"。调用线程无法访问此对象,因为它属于另一个线程。对象"System.Windows.Controls"出错。标记文件PresentationFramework中的边框。Aero, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, ProcessorArchitecture=MSIL;component/themes/Aero .normalcolor.xaml'。"

嗯,我想要的是完全隔离这个单一的对话框,所以它将有自己的资源(事实上,只有网格与ProgressBar和两个textblock在它),而不是使用其他任何东西。有办法做到这一点吗?

注:或者也许有人知道如何确定哪个刷资源是有问题的?因为我只有这个例外,没有别的了……问题的真正根源是什么?

UPD:表示ProgressBar。它的样式使用一些非冻结的画笔,并且它绑定到线程。

我猜导致你出现问题的刷是在较早的时间在主UI线程上实例化的,这就是为什么你看到你的错误。我认为你可能需要重写对话框中所有控件的控件模板,并确保你冻结了所有的画笔。

像这样:

<LinearGradientBrush freezable:Freeze="True" 
xmlns:freezable="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options" 
/>

而且,我相信在您的窗口关闭后,调度程序将继续运行。你需要手动关闭它。像这样:

_dialogWindow.Closed += (sender, e) => _dialogWindow.Dispatcher.InvokeShutdown();

最新更新