WPF 是否可以在后台加载 UI 的一部分?

Is it possible with WPF to load a part of the UI in the background?

我想在我的 WPF 应用程序中显示一个网络。 但总是 window 冻结渲染。 我使用 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" />

没有操作系统允许从另一个线程修改 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 需要这么长时间来显示图形?

将 GraphLayout 的 AsyncCompute 属性 设置为 true :

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

GraphSharp was abandoned 6 years ago if not more. Codeplex itself shut down and now, the only available source code is either the archived source or forks on Github, like this one.

The examples 在这个 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为真时,控件uses a BackgroundWorkerLayout()方法在后台执行操作

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