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