Подтвердить что ты не робот

Что именно делает Panel.IsItemsHost?

Я не могу найти хорошую документацию для прикрепленного свойства Panel.IstItemsHost. Я вижу много примеров того, как люди устанавливают его в шаблоне ItemsContainer для ItemsControl, но не-документация в MSDN не объясняет, почему или какие преимущества предоставляет свойство настройки. Я создал много контейнеров, которые НЕ устанавливают это свойство, но еще не заметили никаких негативных последствий.

4b9b3361

Ответ 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". Есть два способа указать, какая это панель:

  1. ItemsPresenter в ControlTemplate, затем установите свойство ItemsPanel или...
  2. 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 поскольку последнее, хотя и допустимо, просто добавит ненужную сложность без какой-либо реальной выгоды.

Надеюсь, это проясняет, что именно происходит.