DataGrid с элементами из PowerShell очень медленно работает при большом размере источника - PullRequest
0 голосов
/ 16 мая 2019

Вот простая программа WPF (большая часть кода находится в коде):

MainWindow.xaml * * 1004

<Window x:Class="WpfTextBlockInlineDataGridPSProcessSource.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfTextBlockInlineDataGridPSProcessSource"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>

    </Grid>
</Window>

MainWindow.xaml.cs

using System.Diagnostics;
using System.Linq;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;

using static System.Console;

namespace WpfTextBlockInlineDataGridPSProcessSource
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();


            var runspace = RunspaceFactory.CreateRunspace(InitialSessionState.CreateDefault());

            runspace.Open();

            var ps = PowerShell.Create();

            ps.Runspace = runspace;

            // var result = ps.AddScript("get-process").Invoke();

            var result = ps.AddScript("get-process | select-object -first 20").Invoke();


            WriteLine(result.Count);


            if (result.All(elt => elt.BaseObject is Process))
            {

                var data_grid = new DataGrid()
                {
                    ItemsSource = result,

                    IsReadOnly = true,

                    AutoGenerateColumns = false
                };

                data_grid.Columns.Add(new DataGridTextColumn()
                {
                    Header = "ProcessName",
                    Binding = new Binding("ProcessName"),
                });

                var text_block = new TextBlock();

                var scroll_viewer = new ScrollViewer();

                scroll_viewer.Content = text_block;

                text_block.Inlines.Add(data_grid);

                text_block.Inlines.Add(new LineBreak());

                var dock_panel = new DockPanel();

                dock_panel.Children.Add(scroll_viewer);

                Content = dock_panel;
            }
        }
    }
}

Для создания этой тестовой программы вам понадобится пакет System.Management.Automation.dll nuget.

Вот как это выглядит при запуске:

enter image description here

Обратите внимание, что DataGrid ItemsSource установлен на результат команды PowerShell.

В этом случае мы отображаем только 20 Process объектов в DataGrid.

Программа содержит всего 20 пунктов и быстро откликается.

Если мы изменим эту строку:

var result = ps.AddScript("get-process | select-object -first 20").Invoke();

на следующее:

var result = ps.AddScript("get-process").Invoke();

программа перестает отвечать на запросы. Обратите внимание, что в моей системе в списке более 370 процессов; результаты могут отличаться в вашей системе.

Как заставить программу реагировать на большое количество предметов?

Обратите внимание, что особое расположение элементов WPF:

DockPanel -> ScrollViewer -> TextBlock -> Inline -> DataGrid

предназначен для имитации другой программы, в которой эта предназначена для демонстрации проблемы. Вот почему она настроена таким образом.

Если в вашей системе недостаточно процессов для замедления, вы также можете использовать что-то вроде следующего:

var result = ps.AddScript("get-process | select-object -first 20; get-process | select-object -first 20; get-process | select-object -first 20").Invoke();

Для имитации большего числа процессов. (Рассмотрите возможность получения более 300.)

1 Ответ

0 голосов
/ 16 мая 2019

Установка MaxHeight из DataGrid решила проблему:

var data_grid = new DataGrid()
{
    ItemsSource = result,

    IsReadOnly = true,

    MaxHeight = 800,

    AutoGenerateColumns = false
};

Сейчас это невероятно быстро!

Одна теория состоит в том, что без MaxHeight всяDataGrid показано, таким образом отключая виртуализацию.MaxHeight заставляет ScrollViewer включаться после превышения определенной высоты, что, по-видимому, допускает виртуализацию.

...