1

我想在我的 WPF 应用程序中显示一个网络。但总是在渲染时窗口冻结。我使用Graphsharp 库进行可视化。网络在一个额外的线程中组装。所以它可能是渲染。那么,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" />
4

1 回答 1

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;
}

更新

真正的问题似乎是为什么 GraphLayout 需要这么长时间来显示图形?

AsyncComputeGraphLayout 的属性设置为 true :

<graphsharp:GraphLayout
    Graph="{Binding ElementName=root, Path=Graph}"
    LayoutAlgorithmType="LinLog"
    OverlapRemovalAlgorithmType="FSA"
    HighlightAlgorithmType="Simple" 
    AsyncCompute = "true" />

GraphSharp 早在 6 年前就被抛弃了。Codeplex 本身已关闭,现在唯一可用的源代码是存档的源代码或 Github 上的分支,例如这个

此 repo 上的示例显示有一个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时,Layout()控件的方法使用BackgroundWorker在后台执行操作

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

于 2018-10-04T07:23:35.560 回答