我想在我的WPF应用程序中显示一个网络。 但是窗口总是在渲染时冻结。 我使用Graphsharp-library进行可视化。 网络是在额外的线程中组装的。所以可能是渲染器。 那么,使用WPF是否可以在后台加载部分UI?
我的代码:
_graph = await Task.Run(()=> {
var g = new BidirectionalGraph<object, IEdge<object>>();
foreach (MyItem p in _myItemList)
{
g.AddVertex(p);
}
foreach (MyItem p in _myItemList)
{
foreach (MyItem n in p.Neighbors)
{
g.AddEdge(new Edge<object>(p, n));
}
}
return g;
});
OnPropertyChanged("Graph");
XAML:
xmlns:graphsharp="clr-namespace:GraphSharp.Controls;assembly=GraphSharp.Controls"
[...]
<graphsharp:GraphLayout
Graph="{Binding ElementName=root, Path=Graph}"
LayoutAlgorithmType="LinLog"
OverlapRemovalAlgorithmType="FSA"
HighlightAlgorithmType="Simple" />
答案 0 :(得分:1)
没有操作系统允许从另一个线程修改UI。在您的情况下,尽管您不尝试在后台更新UI,但您是在后台组装图形并设置属性。这里没有UI工作。如果呈现元素绑定到该属性,则它将获得通知,读取该属性并自行更新,所有操作均在UI线程中进行。
虽然代码需要改进。任务不是线程,也没有理由使用冷任务和类似的Task.Start()
。 Start()
不保证任务将在何时运行。该任务仍将安排在线程池线程上执行,并且可能会等待那里没有可用线程。
代码可以简化为:
var graph = await Task.Run(()=> {
var g = new BidirectionalGraph<object, IEdge<object>>();
foreach (MyItem p in _myItemList)
{
g.AddVertex(p);
}
foreach (MyItem p in _myItemList)
{
foreach (MyItem n in p.CallingList)
{
g.AddEdge(new Edge<object>(p, n));
}
}
return g;
};
_graph = graph;
OnPropertyChanged("Graph");
更好的想法是使用适当的属性,而不是修改字段并引发事件:
public BidirectionalGraph Graph
{
get => _graph;
set
{
_graph=value;
OnPropertyChanged(nameof(Graph));
}
}
...
public async Task MyGraphMethod()
{
Graph=graph;
}
更新
real 问题似乎是为什么GraphLayout需要这么长时间才能显示图形?
将GraphLayout的AsyncCompute
属性设置为true:
<graphsharp:GraphLayout
Graph="{Binding ElementName=root, Path=Graph}"
LayoutAlgorithmType="LinLog"
OverlapRemovalAlgorithmType="FSA"
HighlightAlgorithmType="Simple"
AsyncCompute = "true" />
GraphSharp在6年前就被遗弃了。 Codeplex本身已关闭,现在,唯一可用的源代码是存档源代码或Github上的fork,例如this one。
The examples在此回购节目中,有一个AsyncCompute
属性将在后台运行布局算法:
<sample:MyGraphLayout x:Name="Layout" LayoutAlgorithmType="ISOM" OverlapRemovalAlgorithmType="FSA" Graph="{Binding}"
AsyncCompute="true" ShowAllStates="false" HighlightAlgorithmType="Simple">
<sample:MyGraphLayout.LayoutParameters>
<isom:ISOMLayoutParameters Width="1200" Height="1200" />
</sample:MyGraphLayout.LayoutParameters>
</sample:MyGraphLayout>
当AsyncCompute为true时,控件uses a BackgroundWorker的Layout()
方法将在后台执行操作
此属性也存在于原始项目源档案中。