#silverlight #windows-phone-7 #virtualizingstackpanel
#silverlight #windows-phone-7 #virtualizingstackpanel
Вопрос:
Все говорят, что по умолчанию ItemsPanel для ListBox является VirtualizingStackPanel. Я создал класс, производный от ListBox (назовем его MyListBox), и вместо этого по умолчанию используется StackPanel.
Я имею в виду, что я должен принудительно выполнить виртуализацию, например, таким образом:
const string itemsPanelTemplateString = @"
<ItemsPanelTemplate
xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml"" >
<VirtualizingStackPanel/>
</ItemsPanelTemplate>";
MyListBox {
this.ItemsPanel = (ItemsPanelTemplate)
System.Windows.Markup.XamlReader.Load(itemsPanelTemplateString);
}
Я мог бы перепечатать здесь свой класс, но дело не в этом. Я хотел бы знать общий ответ.
Класс не изменяет предопределенного стиля ListBox, но использует собственный класс, производный от ListBoxItem.
Я почти уверен, что существуют некоторые условия для использования виртуализации, поскольку мой коллега сказал, что видел соответствующий код ListBox в прошлом. К сожалению, прямо сейчас у нас нет доступа к отладочным версиям MS dll.
Комментарии:
1. Вы могли бы просто изменить ItemsPanel ListBox с помощью XAML.
2. Конечно. Представленный мной код делает то же самое, хотя и в коде. Но мой вопрос в другом — почему виртуализация не была применена. Я не хочу изучать визуальное дерево каждый раз, когда использую ListBox 🙂
3. Можете ли вы продемонстрировать, как вы определяете, что используется
StackPanel
?4. Два способа: а) Подсчет количества элементов, которые были созданы. (Для большого набора данных, конечно.) б) Удаление визуального дерева. Перечислены имена классов.
5. Хороший класс для сброса визуального дерева можно найти по адресу dl.dropbox.com/u/254416/blog/TreeHelper.cs
Ответ №1:
ListBox и элементы управления, производные от ListBox, по умолчанию будут иметь VirtualizedStackPanel в качестве ItemsPanel, если пользовательский код не изменит это явно.
Однако, если ваш пользовательский ListBox является производным непосредственно от ItemsControl (как указано в фактическом выводе из ListBox), тогда вы получите StackPanel в качестве ItemsPanel по умолчанию.
Может ли это быть в вашем коде? Если нет, пожалуйста, поделитесь своим управляющим кодом.
Комментарии:
1. MyListBox является производным от ListBox, MyListBoxItem — производным от ListBoxItem. Я знаю, что вы цитировали документацию msdn, но это утверждение просто не соответствует действительности. а) Мой пример доказывает это. б) Код ListBox, показанный .Net Reflector, также должен это подтверждать.
Ответ №2:
Решена. Это была моя ошибка:
При переопределении ListBox.При использовании функции appplytemplate() (с целью измерения времени) я забыл вызвать base.OnApplyTemplate(). По-видимому, выбор панели элементов выполняется там.
Опасная ошибка, потому что, казалось бы, все работало.
Спасибо всем, кто пытался помочь.
Ответ №3:
Стиль по умолчанию для ListBox не присваивает шаблон ItemsPanel.
Согласно внутреннему коду, который я вижу в reflector, он OnApplyTemplate
назначит VirtualizingStackPanel
внутреннему, ItemsHost
если ItemsPanel
шаблон не предоставлен.
Возможно, включение кода вашего класса в конце концов может оказаться хорошей идеей.
Комментарии:
1. ItemsPanel не была предоставлена. (Прямо сейчас для него установлено значение VirtualizingStackPanel для принудительного выполнения ожидаемого поведения.) Я бы включил код класса, но в нем 900 строк. И в два раза больше, если я включу код, использующий этот класс. Неважно, я попытаюсь исследовать это дальше и сообщу о результате.
Ответ №4:
Вы можете найти хорошие рекомендации по повышению производительности Listbox на http://blogs.msdn.com/b/slmperf/archive/2010/10/06/silverlight-for-windows-phone-7-listbox-scroll-performance.aspx
Также есть хорошая альтернатива, описанная на http://blogs.msdn.com/b/delay/archive/2010/09/08/never-do-today-what-you-can-put-off-till-tomorrow-deferredloadlistbox-and-stackpanel-help-windows-phone-7-lists-scroll-smoothly-and-consistently.aspx
Еще одна вещь, на которую следует обратить внимание (по-видимому), заключается в том, что вы также получите виртуализацию, только если коллекция, к которой вы привязываетесь, реализует IList
.
Комментарии:
1. Последнее предложение не совсем точное. Если вы привязываете что-либо меньшее, чем IList (ICollection или IEnumerable), то
ItemsControl
просто впитает всю коллекцию в свою собственную внутреннюю реализациюIList
. Оттуда вы все равно получите преимущества виртуализации элементов пользовательского интерфейса. Однако кто-то, использующий, скажем, a,IEnumerable<x>
предоставляемый функцией utalizingyield return
, может быть удивлен тем, что все элементы, сгенерированные функцией, полностью используются с самого начала.2. В этом конкретном примере MyListBox привязывается к ObservableCollection<Customer>.