Panel.IsItemsHost究竟做了什么?

Arm*_*age 35 wpf itemscontrol

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

小智 37

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

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

<ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
      <lol:SwoopPanel />
    </ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
Run Code Online (Sandbox Code Playgroud)

但是,有时这对你不起作用.也许您希望自定义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>
Run Code Online (Sandbox Code Playgroud)

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

  • 使用`IsItemsHost ="True"`而不是`ItemsPresenter`的另一个原因是你可以作为[模板部分]访问它(https://msdn.microsoft.com/en-us/library/system.windows.templatepartattribute (v = vs.110)的.aspx) (3认同)

小智 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属性来完成此操作.


Mar*_*eIV 8

请进一步解释!

上述所有的答案是技术上是正确的,我觉得他们没有说明如何IsItemsPanel相关于ControlTemplate和的存在(或不存在),ItemsPresenter以及相应的ItemsPanel它使用属性。该答案将试图阐明这些问题,并希望阐明何时应该使用或不应该使用它们。

ItemsControls,Panels和IsItemsHost,我的天哪!

An ItemsControl只是显示项目集合的控件。为此,它首先ItemContainer为每个项目生成一个,然后将这些容器插入到特定的“主机”面板中(或从中删除),最后,该面板将这些容器布置出来进行显示。

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

  1. 通过插入ItemsPresenterControlTemplate,然后设置ItemsPanel属性,或...
  2. 通过将一个Panel直接插入ControlTemplate并将其IsItemsHost显式设置为“ True”。

但是,您使用哪个?为什么?请仔细阅读,找出答案!

ItemsPresenter-“随心所欲!”

在典型的ControlTemplatefor中,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>
Run Code Online (Sandbox Code Playgroud)

如您所见,模板中间的ItemsPresentera ScrollViewer中有一个指定的内部。但是,您看不到的是一个实际的面板来布置项目。

因此,如果模板中没有定义面板,它来自哪里?这就是ItemsPanel属性的来源。顾名思义,此属性定义将使用哪个面板托管和布置项目。但是,它没有说该面板在中的位置ControlTemplate

这使我们回到了ItemsPresenter。简而言之,它是一个占位符,实际上表示“ ItemsPanel设置属性后,我将在此处插入该面板并将其IsItemsHost自动设置为'True'。”

ItemsPresenter在模板中使用的优点ItemsControl是,您可以使控件的使用者很容易地替换面板, 而不必完全重新为整个控件模板。

IsItemsHost-“我的路还是高速公路!”

但是,如果您不希望某人能够更改面板,因为您的控件取决于某些自定义面板实现,而其他任何因素都会破坏功能,该怎么办?在这种情况下,你使用ItemsPresenter你的模板。相反,您需要指定要使用的确切面板。

这就是IsItemsHost财产发挥作用的地方。在中的面板上进行设置时ControlTemplate,它告诉ItemsControl您使用该特定面板来托管生成的容器,而不管ItemsPanel设置为什么。

这是与上述相同的示例,但不是ItemsPresenter,而是硬编码a 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>
Run Code Online (Sandbox Code Playgroud)

在这种情况下,由于模板不使用ItemsPresenter,而是直接包含IsItemsHost设置为'True' 的面板,因此用户无法完全替换整个面板而无法更改该面板ControlTemplate。设置ItemsPanel属性实际上将被忽略。

把这一切带回家...

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

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

注意:从技术上讲,存在第三种情况,这可能是更常见的情况:您不是控件创建者来创建要由其他用户使用的东西,而是只是重新模板化ItemsControl(例如说出ListBox)以供自己专用应用。

在这种情况下,由于您是控件的最终使用者,因此您很可能不必担心下游的其他使用者需要更换面板,因此完全可以直接在模板中指定面板(完全如此,并将其设置为IsItemsHosttrue),而不必担心使用后者ItemsPresenter及其关联的ItemsPanel属性(虽然有效),只会增加不必要的复杂性而没有任何实际好处。

希望这可以弄清楚到底发生了什么。