Сортировка DataGrid очень медленная, когда ItemsControl также связывается с тем же ItemsSource - PullRequest
0 голосов
/ 06 марта 2012

У меня есть DataGrid, привязанный к наблюдаемому списку объектов. Если к этому списку привязан также ItemsControl, производительность сортировки (щелкнув заголовок DataGrid) будет очень плохой (порядка нескольких секунд для примера ниже). Если ItemsControl не привязан к одному и тому же списку, сортировка выполняется мгновенно.

Вот пример кода, демонстрирующий такое поведение

namespace LargeDataGridViewTest
{
    public partial class MainWindow
    {
        public MainWindow()
        {
            InitializeComponent();
            DataContext = new MainPresenter();
        }
    }

    public class MainPresenter : INotifyPropertyChanged
    {
        private readonly ObservableCollection<Item> _items = new ObservableCollection<Item>();
        public IEnumerable<Item> Items { get { return _items; } }

        public MainPresenter()
        {
            for (var i = 0; i < 10000; i++)
                _items.Add(new Item());
        }
    }

    public class Item : INotifyPropertyChanged
    {
        public int Random { get; private set; }
        private static readonly Random Rand = new Random();

        public Item()
        {
            Random = Rand.Next(0, 1000000);
        }
    }
}

и соответствующий XAML

<Window.Resources>
    <DataTemplate DataType="{x:Type LargeDataGridViewTest:MainPresenter}">
        <DockPanel>
            <DataGrid ItemsSource="{Binding Items}"/>
            <!--ListBox ItemsSource="{Binding Items}"/-->
            <ItemsControl ItemsSource="{Binding Items}"/>
        </DockPanel>
    </DataTemplate>
</Window.Resources>

<ContentPresenter Content="{Binding}"/>

Если вместо ItemsControl я использую ListBox, производительность сортировки будет хорошей. Если я использую ListBox, но получаю доступ к лежащему в его основе ItemsControl, например, изменяя ItemsPanelTemplate, производительность снова ухудшается.

Если я возьму поверхностную копию списка (ссылаясь на те же элементы) и вместо этого свяжу ItemsControl с этим, производительность снова будет в порядке.

Запуск медленной привязки ItemsControl и быстрой привязки ListBox через профилировщик EQATEC не показывает разницы в производительности, кроме времени приложения верхнего уровня.

Кто-нибудь знает, что здесь происходит?

EDIT

Часть ответа, похоже, заключается в том, что ItemsControls не виртуализированы и, следовательно, должны рисовать все свои элементы, а не только видимые. В этом случае, почему все элементы ItemsControl перерисовываются при сортировке DataGrid (даже если режим привязки ItemsControl - OneTime)? И как я могу остановить это, влияя на производительность сортировки DataGrid?

Ответы [ 2 ]

0 голосов
/ 06 марта 2012

Виртуализация - это ключ!

ItemsControls не виртуализируются по умолчанию, и когда сетка данных сортирует коллекцию Items, представление коллекции по умолчанию сортируется, и такая же сортировка применяется и к другим ItemsControl.Но в ItemsControl не реализована виртуализация, и поэтому он не только сортирует элементы, но и отображает их в своем контейнере элементов.ListBox работает лучше, поскольку в нем реализована виртуализация по умолчанию.

Для этого исправление quick имитирует ListBox, чтобы выглядеть как ItemsControl.Это можно сделать, избавившись от выбранных цветов в списке.

   <ListBox ItemsSource="{StaticResource MyData}" DisplayMemberPath="ID">
       <ListBox.ItemContainerStyle>
            <Style TargetType="{x:Type ListBoxItem}">
                <Style.Resources>
                    <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}"
                                     Color="Transparent"/>
                </Style.Resources>
                <Style.Triggers>
                    <Trigger Property="IsSelected" Value="True">
                        <Setter Property="Foreground" Value="Black"/>
                    </Trigger>
                </Style.Triggers>
            </Style>
        </ListBox.ItemContainerStyle>
    </ListBox>
0 голосов
/ 06 марта 2012

Я подозреваю, что это потому, что и DataGrid, и ListBox виртуализируют свои элементы по умолчанию, а ItemsControl - нет.

Это означает, что DataGrid и ListBox создают толькоОбъекты пользовательского интерфейса, которые видны на экране, в то время как ItemsControl создаст все 10 000 объектов пользовательского интерфейса.

Чтобы зафиксировать производительность, виртуализирует ItemsControl.Вот основные необходимые элементы, хотя за подробностями обращайтесь к связанному вопросу.

<ItemsControl
    VirtualizingStackPanel.IsVirtualizing="True" <!-- needed -->
    ScrollViewer.CanContentScroll="True" <!-- needed -->
    ... >
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <VirtualizingStackPanel /> <!-- needed -->
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.Template>
        <ControlTemplate>
            <ScrollViewer>  <!-- needed -->
                <ItemsPresenter  />
            </ScrollViewer>
        </ControlTemplate>
    </ItemsControl.Template>
</ItemsControl>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...