Я пытаюсь создать Panel или ItemsControl, которые будут отображать элементы в виде:

Заголовок 1

  • Подпункт 1
  • Подпункт 2
  • Подпункт 3

Заголовок 2

  • Подпункт 1
  • Подпункт 2

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

Я добился определенного прогресса в работе с MeasureOverride и ArrangeOverride, но продолжаю заходить в тупик. Это действительно расстраивает, потому что это что-то тривиальное с вычислительной точки зрения, но кошмар для выполнения в WPF/Silverlight. Если вы когда-либо работали с пакетами отчетов, концепция очень похожа на эту.

Я постоянно возвращаюсь к тому факту, что не могу определить высоту до тех пор, пока не добавлю дочерние элементы в элемент управления (используя Dispatcher.BeginInvoke).

Есть ли у кого-нибудь предложения по выполнению этого? Заранее спасибо!


Изменить

[WPF] Проблема с созданием ObservableCollection и ListBoxItem DataTemplate

Эта ссылка выше очень похожа на то, что предложил mdm20, но я все еще застрял. Каждый раз, когда я пытаюсь получить ActualHeight, он возвращает 0. Кроме того, ItemContainerGenerator в Silverlight 3 возвращает значение null для контейнера, если я не оберну вызов в операцию Dispatcher.BeginInvoke.

1
Page 13 Май 2009 в 00:21
Попробуйте использовать это.UpdateLayout()
 – 
DmitryBoyko
11 Май 2012 в 00:56

2 ответа

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

    Size maxSize = new Size(0, 30);
    UIElement templateRoot = template.LoadContent() as UIElement;
    templateRoot.Measure(maxSize);
    Size size = templateRoot.DesiredSize;

Однако для этого в шаблоне должна быть указана высота. Я думаю, вас волнует только высота, поэтому я оставил ширину 0.

Как только вы получите высоту шаблона, вам, вероятно, придется настроить какую-то карту, которая отслеживает, какие объекты находятся на той или иной странице. Это нужно будет воссоздавать каждый раз, когда изменяется размер или источник элементов.

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

Вот как я бы попытался это сделать .. если это вообще имеет смысл :)

0
mdm20 13 Май 2009 в 17:56

Действительно, невозможно напрямую измерить UIElement, пока вы его не сконструируете, но вы можете сконструировать элементы списка таким образом, чтобы заранее знать, сколько места они займут. Например, вы можете использовать Grid для размещения каждого из элементов со строкой известной высоты (например, headerHeight) для заголовка и строками известной высоты для каждого из подэлементов (например, subitemHeight). Затем вы можете рассчитать высоту каждого элемента по формуле headerHeight + numSubitems * subitemHeight. Кроме того, если вы знаете, что количество элементов будет довольно небольшим, скажем, менее 1000, вы можете просто захотеть создать их все заранее, поскольку на этом этапе потеря производительности может быть допустимой.

Я согласен, что подобные вещи могут раздражать, но именно гибкость фреймворка создает проблему. Именно эта проблема с вычислением высоты и затрудняет создание плавно прокручиваемого, но все же виртуализированного списка элементов в ListBox или ListView.

0
PeterAllenWebb 13 Май 2009 в 18:08