在ItemsControl中为每个项包装一些内容

7
假设我有一个不同类的对象集合。每个类都有其UserControl DataTemplated在一个资源文件中。
现在我想使用ItemsControl来显示这个集合,但我希望每个项周围都有一个Border或Expander。
我期望像这样的东西可以工作:
<ItemsControl ItemsSource="{Binding MyObjects}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel Orientation="Horizontal"/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Border BorderBrush="Black" BorderThickness="3">
                <ContentPresenter/>
            </Border>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

但是 ContentPresenter 似乎选择了 ItemTemplate,因为我遇到了堆栈溢出的问题。
如何在 ItemTemplate 中获取每个项目的 DataTemplate?

我认为你需要提供一些关于你遇到的错误的细节。你的输出窗口提供了任何线索吗? - benPearce
我有一个按钮,可以将一个项目添加到MyObjects中。但是当我点击它后,输出中没有任何新内容。我从WindowsBase.dll中得到了System.StackOverflowException异常。没有可用的源代码,也没有反汇编来显示给我,也没有异常本身的详细信息。(“无法评估表达式,因为当前线程处于堆栈溢出状态”)。在VS中的调用堆栈并没有给我任何东西。但是如果我从ItemTemplate中删除ContentPresenter,那么每个项目只会得到一个空的边框,而没有堆栈溢出。 - Guge
2个回答

15

通常你可以通过对项容器进行模板化来实现这一点。但问题在于“通用”的ItemsControl使用ContentPresenter作为其项容器。因此,即使您尝试使用ItemContainerStyle设置样式,您也会发现无法提供模板,因为ContentPresenter不支持控件模板化(它支持数据模板化,但这里不适用)。

要使用可模板化的容器,您将需要从ItemsControl派生,就像这个示例中所示。

另一种选择可能只是使用ListBox控件。然后,您可以通过设置样式的ListBoxItem模板来提供自定义模板。

您可以在这里了解更多关于容器的内容。

(在得到您的许可后,我将解决方案添加到了您的答案中,Guge)

    <ListBox ItemsSource="{Binding MyObjects}" Grid.Column="1">
        <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel Orientation="Horizontal"/>
            </ItemsPanelTemplate>
        </ListBox.ItemsPanel>
        <ListBox.ItemContainerStyle>
            <Style TargetType="{x:Type ListBoxItem}">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type ListBoxItem}">
                            <Border BorderBrush="Black" BorderThickness="3">
                                <ContentPresenter/>
                            </Border>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </ListBox.ItemContainerStyle>
    </ListBox>

非常感谢。我有时会忽略模板可以成为样式的一部分这一点。这似乎有些违反直觉,但希望这只是存在于我的脑袋里。 - Guge
这是反直觉的,至少与其他技术相比如此!最终需要记住的是:样式可以设置任何属性,而模板本身只是另一个属性(这就是WPF的“魔法”)。 - Jack Ukleja

2

我只会做以下操作:

<ItemsControl.ItemTemplate>
    <DataTemplate>
        <Border BorderBrush="Black" BorderThickness="3">
            <ContentControl Content={Binding} />
        </Border>
    </DataTemplate>
</ItemsControl.ItemTemplate>

由于DataTemplate标记内的数据上下文是源集合中的一个项目,因此我们可以使用ContentControl来显示此项目。{Binding}表示我们绑定到整个数据上下文。所有项目的DataTemplate将隐式应用,就像我们没有指定ItemsControl.ItemTemplate一样。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接