Panel.IsItemsHost究竟做了什么?

时间:2010-05-18 17:44:49

标签: wpf itemscontrol

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

3 个答案:

答案 0 :(得分:36)

说我有一个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,第一种方式更容易。接受你的选择,真的。我从来没有亲自以第二种方式完成它,但我认为可能有几个地方可能有用。

答案 1 :(得分: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属性来完成的。

答案 2 :(得分:2)

更多详细信息,请!

尽管以上所有答案在技术上都是正确的,但实际上它们缺少说明IsItemsPanelControlTemplate的相关性以及{{1 }}元素和ItemsPresenter属性。

随心所欲!

ItemsPanel这样的ControlTemplate的典型ItemsControl中,模板定义了一个称为ListBox的元素。这是ItemsPresenter模板的简化摘录:

ListBox

如您所见,模板的中间指定了一个<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属性的来源。顾名思义,该属性定义了将用于托管和布置项目的面板。但是,它没有说该面板在模板中的位置。这使我们回到了ItemsPanel。实质上,它是ItemsPresenter中的占位符,上面写着:“当您设置ControlTemplate时,我将其放在此处并将其ItemsPanel设置为true!”

IsItemsHost模板中使用ItemsPresenter的优势在于,您可以轻松地使控件的使用者替换ItemsControl,而不必完全重新模板您的整个控制。

我的路还是高速公路!

但是,如果您不希望某人因为需要一些自定义实现而能够更改您的面板,而其他任何事情都会破坏该功能,该怎么办?在这种情况下,您 不要 在模板中使用ItemsPanel。您可以直接定义面板。这就是ItemsPresenter发挥作用的地方。

与上面的示例相同,但是它不是IsItemsHost,而是硬编码ItemsPresenter来布置项目。我们通过在面板上设置SpecializedPanel属性来指示该面板用于托管项目。

IsItemsHost

在这种情况下,由于没有<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> ,并且模板直接定义了要用于项目的面板,因此用户无法完全替换整个{{ 1}}。

总结...

回顾一下,如果您是控制作者,并且想让用户能够交换用于布置项目的面板,请使用ItemsPresenterControlTemplate定义模板(并且不要忘记通过ItemsControl属性定义要使用的默认面板。)

如果您想“锁定”控件使用的面板,请不要在模板中使用ItemsPresenter。而是直接指定要用于托管项目的面板,并将其ItemsTemplate属性设置为'True'

  

注意:从技术上讲,存在第三种情况,这可能是更常见的情况:您不是控件的作者,而是只是将ItemsPresenter之类的模板重新模板化以供您在特定页面/屏幕上使用。在这种情况下,由于您不必担心下游的其他人,因此最好直接使用IsItemsHost指定面板,而不用担心ListBox / IsItemsHost组合或其增加的复杂性。

     

这是因为您的本地更改不会影响控件的任何其他用法,因为您没有更改默认的ItemsPanel。您只需针对自己的特定实例进行更改。

     

也就是说,您可以仍然使用ItemsPresenter / ControlTemplate组合,而纯粹主义者则认为这是正确的方法,但是除非您实际上需要灵活下游有其他人根据他们的需要换面板(​​即,您正在应用的根目录重新模板ItemsPanel以使布局看起来不错,但是应用中其他地方的消费者可能仍需要换出面板)面板以显示特定屏幕),只是为您自己添加了更多工作。

希望这可以清楚地说明正在发生的事情。