避免在ItemsControl中使用ContentPresenter

8
有没有办法避免ItemsControl在我的项中包装ContentPresenter的生成?我的ItemsControl绑定了一个VM属性,我正在使用一个DataTemplate在我的ItemControl资源中(没有x:Key)来自定义我的集合对象的外观。这一切都很好,但是通过Snoop检查发现,所有我的集合对象都被包裹在ContentPresenter内而不是直接添加到面板中。这个事实给我带来了一些其他问题。有没有办法避免额外的包装?
以下是XAML:
<ItemsControl ItemsSource="{Binding Path=Children}">
  <ItemsControl.Resources>
    <DataTemplate DataType="{x:Type vm:Ellipse}">
      <Ellipse Fill="{Binding Fill}" Stroke="{Binding Stroke}" />
    </DataTemplate>
  </ItemsControl.Resources>
  <ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
      <Canvas Focusable="true" Margin="10" FocusVisualStyle="{x:Null}" />
    </ItemsPanelTemplate>
  </ItemsControl.ItemsPanel>
  <ItemsControl.ItemContainerStyle>
    <Style>
      <Setter Property="Canvas.Left" Value="{Binding XLoc}" />
      <Setter Property="Canvas.Top" Value="{Binding YLoc}" />
      <Setter Property="Canvas.ZIndex" Value="{Binding ZOrder}" />
    </Style>
  </ItemsControl.ItemContainerStyle>
</ItemsControl>

你可能可以创建一个派生自 ItemsControl 的类,并重写 GetContainerForItemOverride 方法,以便直接返回一个 Ellipse 控件。 - Clemens
@Clemens:它不会期望我返回一个容器而不是实际要显示的项(另一方面,该项由DataTemplate管理)吗? - dotNET
否则你将不再拥有DataTemplate,而需要使用ContentPresenter。 - Clemens
1个回答

6

您可以创建一个派生的ItemsControl并重写它的GetContainerForItemOverride方法:

public class MyItemsControl : ItemsControl
{
    protected override DependencyObject GetContainerForItemOverride()
    {
        return new Ellipse();
    }
}

你的 ItemsControl XAML 不再设置 ItemTemplate,并且有一个直接针对椭圆形的 ItemContainerStyle

<local:MyItemsControl ItemsSource="{Binding Items}">
    <local:MyItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas/>
        </ItemsPanelTemplate>
    </local:MyItemsControl.ItemsPanel>
    <local:MyItemsControl.ItemContainerStyle>
        <Style TargetType="Ellipse">
            <Setter Property="Width" Value="100"/>
            <Setter Property="Height" Value="100"/>
            <Setter Property="Fill" Value="{Binding Fill}"/>
            <Setter Property="Stroke" Value="{Binding Stroke}"/>
            <Setter Property="Canvas.Left" Value="{Binding XLoc}"/>
            <Setter Property="Canvas.Top" Value="{Binding YLoc}"/>
            <Setter Property="Panel.ZIndex" Value="{Binding ZOrder}"/>
        </Style>
    </local:MyItemsControl.ItemContainerStyle>
</local:MyItemsControl>

作为一个提示,在绘制以XLoc和YLoc为中心的椭圆时,您应该将Ellipse控件替换为具有EllipseGeometry的Path。

嗯...有一件事:这个ItemsControl绑定到一个包含多种类型对象的集合中,其中之一是椭圆形。GetContainerForItemOverride似乎没有告诉我它需要哪个对象的容器。是否有一种方法可以放置一个switchif并每次返回适当的对象? - dotNET
1
据我所知,没有可以替代的。如果您使用Path而不是Ellipse,则可以将其Data属性绑定到来自视图模型的不同几何形状。但说实话,为不同的视图模型项使用不同的视图项正是项目容器存在的原因。因此,您应该只保留标准的ItemsControl,并通过项目类型选择DataTemplates,或者通过ItemTemplateSelector选择默认DataTemplates。 - Clemens

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