Panel.IsItemsHost 到底做了什么?

发布于 2024-09-01 15:59:27 字数 160 浏览 1 评论 0原文

Panel.IstItemsHost 附加属性的用途是什么?

我看到很多人在 ItemsControlItemsContainer 模板上设置它的例子,但 MSDN 上的非文档并没有解释设置属性的原因或优势。

What is the Panel.IstItemsHost attached property used for?

I see plenty of examples of people setting it on the ItemsContainer template for an ItemsControl, but the un-documentation over at MSDN does not explain why or what advantages setting property confers.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

飘然心甜 2024-09-08 15:59:27

假设我有一个 ItemsControl。我想使用一个自定义面板,当您滚动时,该面板可以将项目快速进出;它称为 SwoopPanel。现在,我如何告诉 ItemsControl 使用我的 SwoopPanel 来包含它创建的模板?

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

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

但是,有时这对您不起作用。也许您希望自定义 SwoopPanel 在 UI 中的呈现方式,而解决此问题的唯一方法是更改​​ ItemsControl 的控件模板。现在,您可以将 SwoopPanel 直接添加到控件模板中,并使用该属性将其标记为 ItemsHost,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>

您是否必须以一种方式或另一种方式进行?不是,其中一个比另一个更有优势吗?好吧,第二种方式可以让你更好地控制 UI,第一种方式更容易。真的,你自己选择吧。我个人从未以第二种方式做过,但我认为它可能在一些地方有用。

Say I have an ItemsControl. I want to use a custom panel that swoops items in and out as you scroll; its called a SwoopPanel. Now, how do I tell the ItemsControl to use my SwoopPanel to contain the templates it creates?

The quick way is to set the ItemsPanel on the ItemsControl:

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

However, sometimes that doesn't work for you. Maybe you wish to customize how the SwoopPanel is presented in the UI, and the only way to get around this is to change the control template of the ItemsControl. Now you can add your SwoopPanel directly to the control template and, using the property, mark it as the ItemsHost that the ItemsControl will put all the templated items it creates.

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

Do you have to do it one way or the other? No. Is one more advantageous than the other? Well, the second way allows you more control of the UI, the first way is easier. Take your pick, really. I've never personally done it the second way, but I think there might be a couple of places where it might be useful.

红尘作伴 2024-09-08 15:59:27

请更多解释!

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

ItemsControls、Panels 和 IsItemsHost,天哪!

ItemsControl 只是一个显示项目集合的控件。它通过首先生成单独的容器*来直观地表示项目,然后将这些容器交给特定的面板来布局以在屏幕上显示。添加或删除项目时,ItemsControl 会根据需要在面板中添加或删除相应的容器。

注意:如果某个项目已经是容器类型的实例(由 IsItemItsOwnContainer 覆盖 ItemsControl) - 即添加一个 ListBoxItem< /code> 实例到 ListBoxItems 集合 - 该项目只是按原样直接传递到面板,充当其自己的容器。

用于托管和布局容器的特定面板是 ItemControl 的控件模板中找到的第一个面板,其 IsItemsHost 属性设置为“True”。

有两种方法可以指定哪个面板:

  1. 通过将 ItemsPresenter 插入到 ControlTemplate 中,作为 ItemsPanel 指定的面板的占位符 属性。 (这是最常见的方式。)

  2. 通过将 Panel 直接插入到 ControlTemplate 中,并将其 IsItemsHost 属性显式设置为 正确

但您使用哪个以及为什么?请继续阅读以找出答案!

ItemsPresenter - “随心所欲!”

ItemsControl(例如 ListBox)的典型 ControlTemplate 中,模板在其内部某处指定一个 ItemsPresenter。下面是显示其使用方式的简化摘录:

<Border x:Name="Bd"
    Background="{TemplateBinding Background}"
    BorderBrush="{TemplateBinding BorderBrush}"
    BorderThickness="{TemplateBinding BorderThickness}">

    <ScrollViewer Focusable="false" Padding="{TemplateBinding Padding}">
        <ItemsPresenter />
    </ScrollViewer>

</Border>

如您所见,模板中间的 ScrollViewer 内部指定了一个 ItemsPresenter。然而,您看不到的是用于布置项目的实际面板。

那么如果模板中没有定义面板,那么它从哪里来呢?这就是 ItemsPanel 属性的用武之地。顾名思义,该属性定义了将使用哪个面板来托管和布局项目。但它没有说明该面板出现在 ControlTemplate 中的位置。

这让我们回到了 ItemsPresenter。简而言之,它是一个占位符,本质上是“当设置 ItemsPanel 属性时,我将在此处插入该面板并将其 IsItemsHost 设置为 True 自动。”

ItemsControl 模板中使用 ItemsPresenter 的优点是,您可以让控件的使用者非常轻松地替换面板 无需完全重新模板化整个控件。

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

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

这就是 IsItemsHost 属性发挥作用的地方。当在 ControlTemplate 中的面板上设置时,它告诉 ItemsControl 使用该特定面板来托管生成的容器,无论 ItemsPanel 是什么设置为。 ItemsPanel 属性基本上被忽略。

直接在模板中指定面板的另一个好处是您可以命名它并像任何其他模板部分一样访问它。

这是与上面相同的示例,但它不是使用 ItemsPresenter,而是硬编码 SpecializedPanel 来布置项目。我们通过将其 IsItemsHost 属性设置为 True 来指示这是我们想要用来托管项目的面板,最后,我们给它一个名称,以便我们可以直接从代码访问它。

<Border x:Name="Bd"
    Background="{TemplateBinding Background}"
    BorderBrush="{TemplateBinding BorderBrush}"
    BorderThickness="{TemplateBinding BorderThickness}">

    <ScrollViewer Focusable="false" Padding="{TemplateBinding Padding}">
        <SpecializedPanel name="PART_MainPanel" IsItemsHost="True" />
    </ScrollViewer>

</Border>

在本例中,由于模板不使用 ItemsPresenter 而是直接包含一个其 IsItemsHost 设置为 True 的面板,因此没有用户无需完全替换整个 ControlTemplate 即可更换该面板。 (如前所述,ItemsPanel 属性将被忽略。)

将其全部带回家...

回顾一下,如果您是控件作者并希望为控件的使用者提供更换控件的灵活性用于布置项目的面板,然后使用 ItemsPresenter 为您的 ItemsControl 定义模板。确保还在模板中设置 ItemsPanel 属性以指定默认面板。

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

注意:从技术上讲,还有第三种情况,这可以说更常见:您不是创建供其他用户使用的内容的控件作者,而只是重新模板化 ItemsControl (例如 ListBox),用于您自己的应用程序中的某些特殊用途。

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

希望这能准确地澄清发生了什么。

More Explanation, Please!

While all of the above answers are technically correct, I feel they don't illustrate how IsItemsPanel correlates to the ControlTemplate and the presence (or absence) of an ItemsPresenter and the corresponding ItemsPanel property which it uses. This answer will attempt to shed light on those things and hopefully clarify when you should, or shouldn't use each.

ItemsControls, Panels and IsItemsHost, Oh my!

An ItemsControl is simply a control that displays a collection of items. It does this by first generating individual containers* to represent the items visually, then it hands those containers over to a specific panel to be laid out for display on screen. As items are added or removed, the ItemsControl adds or removes the corresponding containers from the panel as needed.

Note: If an item is already an instance of the container type (as determined by the result of the IsItemItsOwnContainer override of the ItemsControl)--i.e. you add a ListBoxItem instance to the Items collection of a ListBox--that item is simply passed through as-is directly to the panel, acting as its own container.

The specific panel used for hosting and laying out the containers is the first one found in the ItemControl's control template that has its IsItemsHost property set to 'True'.

There are two ways to specify which panel that is:

  1. By inserting an ItemsPresenter into the ControlTemplate to act as a placeholder for the panel specified by the ItemsPanel property. (This is the most common way.)

  2. By inserting a Panel directly into the ControlTemplate and explicitly setting its IsItemsHost property to True.

But which do you use and why? Read on to find out!

ItemsPresenter - "Have It Your Way!"

In a typical ControlTemplate for an ItemsControl such as a ListBox, the template specifies an ItemsPresenter somewhere inside of it. Here's a simplified excerpt showing how it's used:

<Border x:Name="Bd"
    Background="{TemplateBinding Background}"
    BorderBrush="{TemplateBinding BorderBrush}"
    BorderThickness="{TemplateBinding BorderThickness}">

    <ScrollViewer Focusable="false" Padding="{TemplateBinding Padding}">
        <ItemsPresenter />
    </ScrollViewer>

</Border>

As you can see, there is an ItemsPresenter specified inside of a ScrollViewer in the middle of the template. What you don't see however is an actual panel to lay out the items.

So if there's no panel defined in the template, where does it come from? That's where the ItemsPanel property comes in. As its name suggests, this property defines which panel will be used to host and lay out the items. It doesn't however say where that panel appears in the ControlTemplate.

That brings us back to the ItemsPresenter. In short, it's a placeholder that essentially says "When the ItemsPanel property is set, I'll insert that panel here and set its IsItemsHost to True automatically."

The advantage of using an ItemsPresenter in the template for your ItemsControl is that you're making it very easy for consumers of your control to replace the panel without having to completely re-template your entire control.

IsItemsHost - "My Way or the Highway!"

However, what if you don't want someone to be able to change out your panel because your control depends on some custom panel implementation and anything else will break the functionality? In that case, you don't use an ItemsPresenter in your template. You instead need to specify the exact panel you want to use.

This is where IsItemsHost property comes into play. When set on a panel in the ControlTemplate, it tells that ItemsControl to use that specific panel to host the generated containers, regardless of what ItemsPanel is set to. The ItemsPanel property is essentially ignored.

Another benefit of specifying the panel directly in the template is you can then name it and access it just like any other template part.

Here's the same example as above, but rather than an ItemsPresenter, it hard-codes a SpecializedPanel to lay out the items. We indicate that's the panel we want to use to host the items by setting its IsItemsHost property to True and finally, we give it a name so we can access it directly from code.

<Border x:Name="Bd"
    Background="{TemplateBinding Background}"
    BorderBrush="{TemplateBinding BorderBrush}"
    BorderThickness="{TemplateBinding BorderThickness}">

    <ScrollViewer Focusable="false" Padding="{TemplateBinding Padding}">
        <SpecializedPanel name="PART_MainPanel" IsItemsHost="True" />
    </ScrollViewer>

</Border>

In this case, because the template doesn't use an ItemsPresenter and instead directly includes a panel with its IsItemsHost set to True, there is no way for the user to change out that panel short of completely replacing the entire ControlTemplate. (As mentioned before, the ItemsPanel property is ignored.)

Bringing it all home...

To recap, if you're a control author and want to give consumers of your control the flexibility to swap out the panel used to lay out your items, then define your template for your ItemsControl using an ItemsPresenter. Make sure to also set the ItemsPanel property in the template to specify a default panel.

If however, want to 'lock' which panel your control uses, then do not use an ItemsPresenter in the ControlTemplate. Instead, specify the specific panel you want to use directly in the template, then set its IsItemsHost property to True.

Note: There's technically a third scenario, which is arguably more common: You're not a control author creating something to be consumed by other users, but rather are simply re-templating an ItemsControl (like say a ListBox) for some specialized use in your own application.

In that case, since you are the ultimate consumer of the control, you most likely won't have to worry about other consumers downstream needing to change out the panel, so it's completely fine to simply specify the panel directly in your template (again, setting its IsItemsHost true) and not worry about using an ItemsPresenter and its associated ItemsPanel property as the latter, while valid, would just add unnecessary complexity without any actual benefit.

Hope this clarifies exactly what's going on.

你列表最软的妹 2024-09-08 15:59:27

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

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

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

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

Essentially, what this post says is that if you are replacing the ControlTemplate of a ListBox and want a new layout, set IsItemsHost=true on some panel, e.g. a StackPanel. Then any items in the ListBox will be automatically added as children of the StackPanel. If the orientation of the ListBox is Horizontal, then the ListBox will be horizontal.

The other way is to set the ItemsPanel property of the ListBox to an ItemsTemplate and in that template you have a StackPanel. In this case the ListBox items will be added to the StackPanel children just as in the first case. However, you do not need to set IsItemsHost = true, it will have absolutely no effect. This is done for you by the fact that you are setting the ItemsPanel property.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文