Panel.IsItemsHost究竟做了什么?

问题描述 投票:32回答:3

我找不到Panel.IstItemsHost附加属性的任何好文档。我看到很多人在ItemsControl的ItemsContainer模板上设置它的例子,但在MSDN上的un-documentation并没有解释为什么或设置属性赋予什么优势。我已经构建了大量不设置此属性的容器,但尚未注意到任何不良影响。

wpf itemscontrol
3个回答
37
投票

说我有一个ItemsControl。我想使用一个自定义面板,在滚动时将项目放入和拉出;它叫做SwoopPanel。现在,我如何告诉ItemsControl使用我的SwoopPanel来包含它创建的模板?

快速的方法是在ItemsControl上设置ItemsPanel:

<ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
      <lol:SwoopPanel />
    </ItemsPanelTemplate>
</ItemsControl.ItemsPanel>

但是,有时这对你不起作用。也许您希望自定义SwoopPanel在UI中的显示方式,解决此问题的唯一方法是更改​​ItemsControl的控件模板。现在,您可以将SwoopPanel直接添加到控件模板中,并使用该属性将其标记为ItemsControl将放置它创建的所有模板化项目的ItemsHost。

<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>

你必须以某种方式做到这一点吗?不是。比另一个更有优势吗?好吧,第二种方式可以让你更多地控制UI,第一种方式更容易。接受你的选择,真的。我从来没有亲自以第二种方式完成它,但我认为可能有几个地方可能有用。


12
投票

http://msdn.microsoft.com/en-us/library/system.windows.controls.panel.isitemshost(v=vs.90).aspx

本质上,这篇文章所说的是,如果你要替换ListBox的ControlTemplate并想要一个新的布局,在某些面板上设置IsItemsHost = true,例如一个StackPanel。然后,ListBox中的任何项目将自动添加为StackPanel的子项。如果ListBox的方向是水平,则ListBox将是水平的。

另一种方法是将ListBox的ItemsPanel属性设置为ItemsTemplate,并在该模板中设置StackPanel。在这种情况下,ListBox项目将添加到StackPanel子项中,就像在第一种情况下一样。但是,您不需要设置IsItemsHost = true,它将完全没有效果。您可以通过设置ItemsPanel属性来完成此操作。


8
投票

更多解释,拜托!

虽然上述所有答案在技术上都是正确的,但我觉得它们没有说明IsItemsPanel如何与ControlTemplate以及ItemsPresenter的存在(或缺席)以及它使用的相应的ItemsPanel属性相关联。这个答案将试图揭示这些事情,并希望澄清何时应该或不应该使用每一个。

ItemsControls,Panels和IsItemsHost,哦,我的!

ItemsControl只是一个显示项目集合的控件。它通过首先为每个项目生成一个ItemContainer来实现这一点,然后将这些容器插入(或从中删除)特定的“主机”面板,最后,该面板将容器放出以供显示。

用于托管容器的特定面板是ItemControl层次结构中的第一个面板,其IsItemsHost属性设置为“True”。有两种方法可以指定哪个面板:

  1. 通过将ItemsPresenter插入ControlTemplate,然后设置ItemsPanel属性,或者......
  2. 通过将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设置为'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设置为'True',用户无法更改该面板,完全替换整个ControlTemplate。设置ItemsPanel属性将基本上被忽略。

把它全部带回家......

回顾一下,如果您是一名控制作者,并希望让您的控件的消费者能够更换用于布置项目的面板,请使用ItemsControl为您的ItemsPresenter定义模板。确保还在模板中设置ItemsPanel属性以指定默认面板。

但是,如果想要“锁定”控件使用的面板,请不要在ItemsPresenter中使用ControlTemplate。而是在模板中指定要直接使用的特定面板,然后将其IsItemsHost属性设置为“True”。

注意:技术上有第三种情况,可以说更常见:你不是一个控制作者创造一些东西供其他用户使用,而只是简单地重新模仿ItemsControl(比如说ListBox)用于某些特殊用途你自己的申请。

在这种情况下,由于您是控件的最终消费者,您很可能不必担心下游需要更换面板的其他消费者,因此只需在模板中直接指定面板就完全没问题了(同样,设置它的IsItemsHost是真的)并且不担心使用ItemsPresenter及其相关的ItemsPanel属性作为后者,虽然有效,但会增加不必要的复杂性而没有任何实际的好处。

希望这能确切地说明发生了什么。

© www.soinside.com 2019 - 2024. All rights reserved.