我想在不同的线程上创建一个Grid
元素(创建整个网格是昂贵的)并通过StackPanel
更新Dispatcher
。但是,无论我做什么,调用Dispatcher
总是会抛出InvalidOperationException
。
这是我的代码:
Grid grid = new Grid();
Dispatcher.Invoke(() => stackPanel.Children.Add(grid));
我尝试过的事情:
Closing over a variable [没有工作]
Grid grid = new Grid();
Grid closedOverGrid = grid;
Dispatcher.Invoke(new Action(() => stackPanel.Children.Add(closedOverGrid)));
Using BeginInvoke [没有工作]
//declaring this in another thread.
Grid grid = new Grid();
AddToPanel(grid);
private void AddToPanel(Grid grid)
{
Dispatcher.BeginInvoke((Action)(() =>
{
stackPanel.Children.Add(grid);
}));
}
Using a full declaration with DispatcherPriority [没有工作]
Grid grid = new Grid();
System.Windows.Application.Current.Dispatcher.BeginInvoke(
DispatcherPriority.Background,
new Action(() => stackPanel.Children.Add(grid)));
Tried the .Freeze() method [没有工作]
Grid grid = new Grid();
grid.Freeze(); // Not possible.
真的不可能,或者我错过了什么?感谢您的回答/评论。
答案 0 :(得分:1)
您只能访问最初创建的线程上的控件,因此在后台线程上创建控件然后尝试使用它或在UI线程上修改它不是选项。这就是你得到InvalidOperationException的原因。
真的不可能,或者我错过了什么?
确实可以在 STA 线程上创建一个控件:
The calling thread must be STA, because many UI components require this
...但是你仍然无法在另一个线程上使用该控件,所以这在我的场景中会毫无意义。
所以不,你应该在同一个线程上创建所有控件。这是创建父窗口的线程,即通常是主线程。
此规则有一些非常有限的例外情况。有关详细信息,请参阅以下博客文章:https://blogs.msdn.microsoft.com/dwayneneed/2007/04/26/multithreaded-ui-hostvisual/。如果您的控件不需要某种交互性,您可以使用HostVisual,如本文所述。
您还可以在自己的主题中启动整个顶级窗口:http://reedcopsey.com/2011/11/28/launching-a-wpf-window-in-a-separate-thread-part-1/。
但除此之外,在WPF应用程序中创建多个UI线程没有任何意义。你只需要以某种方式使控件渲染更快,而不是试图将渲染工作卸载到另一个线程,因为这不起作用。