Можно ли с WPF загрузить часть пользовательского интерфейса в фоновом режиме? - PullRequest
0 голосов
/ 03 октября 2018

Я хочу показать сеть в моем WPF-приложении.Но всегда окно останавливается при рендеринге.Я использую Graphsharp-библиотеку для визуализации.Сеть собрана в дополнительной ветке.Так что, вероятно, это будут рендеры.Итак, возможно ли с помощью WPF загрузить часть пользовательского интерфейса в фоновом режиме?

Мой код:

    _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 голосов
/ 04 октября 2018

НЕТ операционной системы позволяет изменять пользовательский интерфейс из другого потока.В вашем случае, хотя вы не пытаетесь обновить пользовательский интерфейс в фоновом режиме, вы собираете график в фоновом режиме и задаете свойство.Там нет работы интерфейса здесь.Если элемент рендеринга связывается с этим свойством, он получит уведомление, прочитает свойство и сам обновится, все в потоке пользовательского интерфейса.

Хотя код нуждается в улучшении.Задачи не являются потоками, и нет причин использовать холодные задачи и тому подобное.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");

A Лучше Идея состоит в том, чтобы использовать правильное свойство вместо изменения полей и создания события:

public BidirectionalGraph Graph 
{
    get => _graph;
    set 
    {
        _graph=value;
        OnPropertyChanged(nameof(Graph));
    }
}
...
public async Task MyGraphMethod()
{
    Graph=graph;
}

ОБНОВЛЕНИЕ

real вопрос, похоже, почему GraphLayout занимает так много времени для отображения графика?

Установите для свойства AsyncCompute GraphLayout значение true:

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

GraphSharp былзаброшен 6 лет назад если не больше.Сам Codeplex отключился, и теперь единственным доступным исходным кодом является либо архивированный исходный код, либо вилки на Github, например этот .

Примеры в этом репо-шоуесть свойство 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, метод элемента управления *1040* использует BackgroundWorker для выполненияоперация в фоновом режиме

Это свойство существует и в исходном архиве исходных проектов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...