我有大量的应用程序设计不好。特别是在启动时,它正在初始化UI线程中的许多服务。问题是初始化可能很耗时,因此UI线程在此期间会冻结。我无法将它移动到后台线程,因为一些服务依赖于它们启动的线程,并且只有太多的代码来检查它逐行发生的位置。
这个想法是在单独的线程中使用单独的Dispatcher显示加载屏幕和ProgressBar:
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,而只是Window,内容设置为ViewModel,资源中设置为DataTemplate
。但是ASAIK在这里并不重要。)
它有效,但似乎使用了一些资源,因此有效地将它们绑定到非主UI线程。后来我收到异常“无法将属性'Background'中的值转换为'System.Windows.Media.Brush'类型的对象。调用线程无法访问此对象,因为另一个线程拥有它。对象'System.Windows出错.Controls.Border'在标记文件'PresentationFramework.Aero,Version = 3.0.0.0,Culture = neutral,PublicKeyToken = 31bf3856ad364e35,ProcessorArchitecture = MSIL; component / themes / aero.normalcolor.xaml'。“
嗯,我想要的是完全隔离这个单一的对话框,以便它有自己的资源(实际上只有Grid with ProgressBar和两个TextBlocks)并且不使用任何其他东西。有没有办法做到这一点?
P.S。或者也许有人知道如何确定哪个Brush资源确实存在问题?因为我只有这个例外,没有别的......问题的根源究竟是什么?
UPD :ProgressBar
。它的风格使用一些非冻结的刷子,它与线程绑定。
答案 0 :(得分:1)
我猜测导致你出现问题的画笔早先在主UI线程上实例化了,这就是你看错的原因。我想您可能必须覆盖对话框中所有控件的控件模板,并确保冻结所有画笔。
这样的事情:
<LinearGradientBrush freezable:Freeze="True"
xmlns:freezable="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options"
/>
此外,我相信调度程序将在您的窗口关闭后继续运行。你需要手动将其关闭..这样的事情:
_dialogWindow.Closed += (sender, e) => _dialogWindow.Dispatcher.InvokeShutdown();