Больше объяснений, пожалуйста!
Хотя все вышеприведенные ответы являются технически правильными, я чувствую, что они не иллюстрируют, как IsItemsPanel
соотносится с ControlTemplate
и наличием (или отсутствием) ItemsPresenter
и соответствующего свойства ItemsPanel
, которое оно использует. Этот ответ попытается пролить свет на эти вещи и, надеюсь, уточнить, когда вы должны или не должны использовать каждый из них.
ItemsControls, Panels and IsItemsHost, Oh my!
ItemsControl
- это просто элемент управления, отображающий коллекцию элементов. Для этого он сначала генерирует ItemContainer
для каждого из этих элементов, затем вставляет эти контейнеры в (или удаляет их) из определенной панели «хоста» и, наконец, эта панель размещает контейнеры для отображения.
Специальная панель, используемая для размещения контейнеров, является первой панелью в иерархии ItemControl
, для которой свойство IsItemsHost
имеет значение True. Есть два способа указать, какая это панель:
- Вставив
ItemsPresenter
в ControlTemplate
, затем установив свойство ItemsPanel
, или ...
- Вставив
Panel
непосредственно в ControlTemplate
и явно указав для IsItemsHost
значение «Истина».
Но что вы используете и почему? Читайте дальше, чтобы узнать!
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
значение« True »."
Преимущество использования ItemsPresenter
в шаблоне для вашего ItemsControl
состоит в том, что вы облегчаете потребителям вашего контроля замену панели без необходимости повторной настройки шаблона. весь ваш контроль.
IsItemsHost - «Мой путь или шоссе!»
Однако что, если вы не хотите, чтобы кто-то мог изменить вашу панель, потому что ваш контроль зависит от какой-то реализации пользовательской панели, и что-то еще нарушит функциональность? В этом случае вы не используете ItemsPresenter
в своем шаблоне. Вместо этого вам нужно указать точную панель, которую вы хотите использовать.
Здесь IsItemsHost
свойство вступает в игру. При установке на панели в ControlTemplate
, он сообщает, что ItemsControl
должен использовать эту конкретную панель для размещения сгенерированных контейнеров, независимо от того, для чего установлено ItemsPanel
.
Вот тот же пример, что и выше, но вместо ItemsPresenter
он жестко кодирует SpecializedPanel
для разметки элементов. Мы указываем, что это панель, которую мы хотим использовать для размещения элементов, установив для свойства 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
, установленной в «Истина», пользователь не может изменить эту панель за исключением полностью замена всего ControlTemplate
. Установка свойства ItemsPanel
будет по существу игнорироваться.
Приносить все домой ...
Напомним, что если вы управляющий автор и хотите дать пользователю возможность поменять панель, используемую для размещения элементов, определите шаблон для вашего ItemsControl
с помощью ItemsPresenter
, а также установите панель по умолчанию для использования через свойство ItemsTemplate
.
Если вместо этого вы хотите заблокировать панель, которую ваш элемент управления использует в этом ControlTemplate
, не используйте ItemsPresenter
. Вместо этого прямо укажите, какую панель вы хотите использовать для размещения своих элементов, и установите для свойства IsItemsHost
значение «True»
.
Примечание: Технически существует третий сценарий, который, возможно, более распространен: вы не автор контрольной программы, создающий что-то, что будет использоваться другими, а скорее просто переписываете ItemsControl
(как, скажем, ListBox
) для использования в вашем собственном приложении.
В этом случае, поскольку вам, скорее всего, не придется беспокоиться о других нижестоящих, нуждающихся в замене панели, вполне нормально указать панель непосредственно в вашем шаблоне (опять же, установив ее IsItemsHost
true). В этом случае использование ItemsPresenter
и связанного с ним свойства ItemsPanel
просто добавит ненужную сложность без какой-либо реальной выгоды.
Надеюсь, это проясняет, что именно происходит.