DataGrid в StackPanel приводит к OutOfMemoryException

У меня есть сетка в окне WPF и элемент управления DataGrid внутри:

<Grid>
    <DataGrid ItemsSource="{Binding AllAuthors}" />
</Grid>

AllAuthors — это ObservableCollection<Author>, а Author — простой класс с несколькими строковыми свойствами. Коллекция содержит около 40 000 объектов в коде. DataGrid открывается довольно быстро (через 1 секунду), и навигация по сетке данных происходит плавно и быстро. Приложение имеет загрузку памяти 35 МБ.

Если я заменю приведенный выше код на...

<StackPanel>
    <DataGrid ItemsSource="{Binding AllAuthors}" />
</StackPanel>

... приложение работает со 100% загрузкой процессора, а объем памяти постоянно увеличивается до 1,5 ГБ, пока приложение пытается отобразить DataGrid. Наконец я получаю OutOfMemoryException.

Я новичок в WPF и теперь думаю, что здесь не так. (Я использую VS2010, .NET 4.0 и встроенный элемент управления DataGrid WPF 4.0)

Спасибо за помощь заранее!


person Slauma    schedule 15.09.2010    source источник
comment
Вы помогли мне найти мою проблему: я управлял всем с помощью Task.run(), и когда я обновлял свою коллекцию и вызывал OnPropertyChanged(), инструмент аварийно завершал работу с тем же поведением (макс. ОЗУ, outofMemoryException). Я часами ищу, чтобы понять, что было не так в моем коде на С#, но, наконец, это произошло из-за того, что поток пользовательского интерфейса создал огромную панель стека! Благодарность   -  person Simon    schedule 05.01.2017


Ответы (1)


Пока он находится в сетке, это не проблема, так как, вероятно, на самом деле генерируется только несколько элементов - те, которые на самом деле видны в данный момент. Это называется виртуализацией пользовательского интерфейса и встроено в несколько ItemsControls в WPF. Поскольку DataGrid довольно мал, на самом деле генерируется не слишком много элементов.

Однако, когда вы помещаете его в StackPanel, вы можете создать макет, в котором StackPanel расширяется до высоты DataGrid, в то время как DataGrid занимает столько места, сколько считает нужным. Нам нужно увидеть полный xaml, чтобы убедиться, что это так. В любом случае, если это так, то теперь "видимых" предметов на самом деле довольно много (т.е. все они). И генерировать 40000 элементов явно не очень хорошая идея.

Вы сравнивали свойство ActualHeight двух DataGrid?

person bitbonk    schedule 15.09.2010
comment
Спасибо за ответ! Я только что сравнил ActualHeight для компоновки Grid и StackPanel (только для 500 элементов), и вы правы: если DataGrid находится в сетке, высота составляет всего 440, если в StackPanel, она увеличивается до более чем 8800. Я' Я также установил EnableRowVirtualization=False в DataGrid для теста, и в этом случае у меня такая же проблема с памятью и производительностью с макетом Grid. Чего я не понимаю, так это почему у меня загрузка памяти превышает 1,5 ГБ. Объекты Author имеют размер менее 200 байт, поэтому с 40000 объектов откуда берутся 1,5 ГБ? - person Slauma; 15.09.2010
comment
Это происходит из всех визуальных элементов WPF, которые создаются для каждого элемента Author на основе ItemTemplate. - person bitbonk; 15.09.2010
comment
Хорошо, я вижу. Я указал Height из 400 в DataGrid, и теперь он также работает с StackPanel. Итак, если я правильно понял, Grid ограничивает элементы управления внутри сетки видимой областью окна, в то время как StackPanel может расширяться до невидимой области окна в соответствии с потребностями различных элементов управления внутри. Это правильно? В любом случае, ваш ответ очень помог. Еще раз спасибо! - person Slauma; 15.09.2010
comment
Это зависит от того, что является родителем Grid/StackPanel. - person bitbonk; 15.09.2010