使用WPF是否可以在后台加载部分UI?

时间:2018-10-03 17:10:37

标签: c# wpf graph-sharp

我想在我的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" />

1 个答案:

答案 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 BackgroundWorkerLayout()方法将在后台执行操作

此属性也存在于原始项目源档案中。