Я не могу найти хорошую документацию для прикрепленного свойства Panel.IstItemsHost. Я вижу много примеров того, как люди устанавливают его в шаблоне ItemsContainer для ItemsControl, но не-документация в MSDN не объясняет, почему или какие преимущества предоставляет свойство настройки. Я создал много контейнеров, которые НЕ устанавливают это свойство, но еще не заметили никаких негативных последствий.
Что именно делает Panel.IsItemsHost?
Ответ 1
Скажем, у меня есть ItemControl. Я хочу использовать настраиваемую панель, которая вворачивает элементы внутрь и снаружи по мере прокрутки; его называют SwoopPanel. Теперь, как я могу указать ItemsControl использовать мой SwoopPanel для размещения шаблонов, которые он создает?
Быстрый способ - установить ItemsPanel в ItemsControl:
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<lol:SwoopPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
Однако иногда это не работает для вас. Возможно, вы хотите настроить, как SwoopPanel представлен в пользовательском интерфейсе, и единственный способ обойти это - изменить шаблон управления ItemsControl. Теперь вы можете добавить SwoopPanel непосредственно в шаблон управления и, используя свойство, пометить его как ItemHost, который ItemsControl поместит все шаблонные элементы, которые он создает.
<Style TargetType="ItemsControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ItemsControl">
<Border CornerRadius="5">
<ScrollViewer VerticalScrollBarVisibility="Hidden">
<lol:SwoopPanel IsItemsHost="True"/>
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Вам нужно сделать это так или иначе? Нет. Это еще одно преимущество, чем другое? Ну, второй способ позволяет вам больше контролировать пользовательский интерфейс, первый способ проще. Возьмите свой выбор, действительно. Я никогда не делал этого по-другому, но я думаю, что может быть несколько мест, где это может быть полезно.
Ответ 2
См. http://msdn.microsoft.com/en-us/library/system.windows.controls.panel.isitemshost(v=vs.90).aspx
По существу, в этом сообщении говорится, что если вы заменяете ControlTemplate из ListBox и хотите новый макет, установите IsItemsHost = true на какой-либо панели, например. StackPanel. Затем любые элементы в ListBox будут автоматически добавлены в качестве дочерних элементов StackPanel. Если ориентация ListBox горизонтальна, то ListBox будет горизонтальной.
Другой способ - установить свойство ItemsPanel ListBox на ItemsTemplate, и в этом шаблоне у вас есть StackPanel. В этом случае элементы ListBox будут добавлены к дочерним элементам StackPanel, как и в первом случае. Однако вам не нужно устанавливать IsItemsHost = true, это не будет иметь абсолютно никакого эффекта. Это делается для вас тем фактом, что вы устанавливаете свойство ItemsPanel.
Ответ 3
Больше объяснений, пожалуйста!
Хотя все вышеперечисленные ответы являются технически правильными, я чувствую, что они не иллюстрируют, как IsItemsPanel
соотносится с ControlTemplate
и наличием (или отсутствием) ItemsPresenter
и соответствующего свойства ItemsPanel
которое он использует. Этот ответ попытается пролить свет на эти вещи и, надеюсь, уточнить, когда вы должны или не должны использовать каждый из них.
Элементы управления, панели и IsItemsHost, о мой!
ItemsControl
- это просто элемент управления, который отображает коллекцию элементов. Для этого он сначала генерирует ItemContainer
для каждого из этих элементов, затем вставляет эти контейнеры в (или удаляет их) из определенной панели "хоста" и, наконец, эта панель размещает контейнеры для отображения.
Конкретная панель, используемая для размещения контейнеров является первой панели находится в ItemControl
иерархии, которая имеет свою IsItemsHost
свойство установлено значение "True". Есть два способа указать, какая это панель:
-
ItemsPresenter
вControlTemplate
, затем установите свойствоItemsPanel
или... -
IsItemsHost
Panel
непосредственно вControlTemplate
и установив дляIsItemsHost
значение "True" в явном виде.
Но что вы используете и почему? Читай дальше что бы узнать!
ItemsPresenter - "Имей свой путь!"
В типичном ControlTemplate
для ItemsControl
таком как ListBox
, шаблон указывает ItemsPresenter
где-то внутри него. Вот упрощенная выдержка, показывающая, как она использовалась:
<Border x:Name="Bd"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
Padding="1" SnapsToDevicePixels="true">
<ScrollViewer Focusable="false" Padding="{TemplateBinding Padding}">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</ScrollViewer>
</Border>
Как вы можете видеть, есть ItemsPresenter
указано внутри ScrollViewer
в середине шаблона. Однако чего вы не видите, так это фактической панели для размещения элементов.
Итак, если в шаблоне не определена панель, откуда она взялась? Именно там появляется свойство ItemsPanel
. Как следует из его названия, это свойство определяет, какая панель будет использоваться для размещения и размещения элементов. Однако в нем не указано, где эта панель появляется в ControlTemplate
.
Это возвращает нас к ItemsPresenter
. Короче говоря, это местозаполнитель, который по сути говорит: "Когда свойство ItemsPanel
установлено, я IsItemsHost
эту панель сюда и автоматически установлю для ее IsItemsHost
значение" True "".
Преимущество использования
ItemsPresenter
в шаблоне дляItemsControl
заключается в том, что потребители вашего элемента управления очень легко заменяют панель без необходимости полностью повторно шаблонировать весь элемент управления.
IsItemsHost - "Мой Путь или Шоссе!"
Однако что, если вы не хотите, чтобы кто-то мог изменить вашу панель, потому что ваш контроль зависит от какой-то реализации пользовательской панели, а что-то еще нарушит функциональность? В этом случае вы не используете ItemsPresenter
в своем шаблоне. Вместо этого вам нужно указать точную панель, которую вы хотите использовать.
Здесь вступает в игру свойство IsItemsHost
. Когда он установлен на панели в ControlTemplate
, он сообщает, что ItemsControl
должен использовать эту конкретную панель для размещения сгенерированных контейнеров, независимо от того, для чего установлен ItemsPanel
.
Здесь тот же пример, что и выше, но вместо ItemsPresenter
он жестко кодирует SpecializedPanel
для размещения элементов. Мы указываем, что панель, которую мы хотим использовать для размещения элементов, устанавливая IsItemsHost
свойства IsItemsHost
значение True.
<Border x:Name="Bd"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
Padding="1" SnapsToDevicePixels="true">
<ScrollViewer Focusable="false" Padding="{TemplateBinding Padding}">
<SpecializedPanel IsItemsHost="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</ScrollViewer>
</Border>
В этом случае, поскольку шаблон не использует ItemsPresenter
и вместо этого напрямую включает в себя панель с IsItemsHost
установленным в значение "True", пользователь не может изменить эту панель, за исключением полной замены всего ControlTemplate
. Установка свойства ItemsPanel
будет по существу игнорироваться.
Принося все это домой...
Напомним, что если вы автор элемента управления и хотите предоставить потребителям вашего элемента управления возможность поменять панель, используемую для размещения элементов, определите шаблон для вашего ItemsControl
с помощью ItemsPresenter
. Не забудьте также установить свойство ItemsPanel
в шаблоне, чтобы указать панель по умолчанию.
Однако, если вы хотите заблокировать панель, которую использует ваш элемент управления, не используйте ItemsPresenter
в ControlTemplate
. Вместо этого укажите конкретную панель, которую вы хотите использовать непосредственно в шаблоне, а затем установите IsItemsHost
свойства IsItemsHost
значение "True".
Примечание. Технически существует третий сценарий, который, возможно, является более распространенным: вы не являетесь автором элемента управления, создающим что-то для использования другими пользователями, а скорее просто повторно шаблонизируете
ItemsControl
(например,ListBox
) для некоторого специализированного использования в ваше собственное приложение.В этом случае, поскольку вы являетесь конечным потребителем элемента управления, вам, скорее всего, не придется беспокоиться о том, что другим потребителям, находящимся ниже по течению, придется менять панель, поэтому вполне можно просто указать панель непосредственно в шаблоне (опять же, устанавливая его
IsItemsHost
true) и не беспокойтесь об использованииItemsPresenter
и связанного с ним свойстваItemsPanel
поскольку последнее, хотя и допустимо, просто добавит ненужную сложность без какой-либо реальной выгоды.
Надеюсь, это проясняет, что именно происходит.