2015-08-03 5 views
4

Есть ли способ избежать генерации ContentPresenter, чтобы ItemsControl обертывал мои предметы? Мой ItemsControl связан с собственностью VM, и я использую DataTemplate в своих ресурсах ItemControl (без x:Key), чтобы настроить внешний вид объектов моей коллекции. Все это прекрасно работает, но проверка через Snoop показывает, что все мои объекты коллекции обернуты внутри ContentPresenter s и не добавляются непосредственно к панели. Этот факт создает для меня некоторые другие проблемы. Есть ли способ избежать дополнительной упаковки?Избегайте ContentPresenter в ItemsControl

Вот 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> 
+0

Возможно, вы можете создать производный элемент ItemsControl и переопределить метод GetContainerForItemOverride (https://msdn.microsoft.com/en-us/library/aa346422 (v = vs.110) .aspx) для прямого возврата эллипса контроль. – Clemens

+0

@Clemens: Не будет ли ожидать, что я верну * * контейнер *, а не фактический элемент, который будет отображаться (с другой стороны, он управляется 'DataTemplate')? – dotNET

+0

У вас больше не будет DataTemplate, иначе вам понадобится ContentPresenter. – Clemens

ответ

4

Вы можете создать производный 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, вы должны заменить элемент управления эллипсом контуром с помощью эллиптической геометрии.

+0

Хммм ... Одно: этот элемент ItemsControl связывается с коллекцией, в которой есть несколько типов объектов, одним из которых является Ellipse. 'GetContainerForItemOverride', похоже, не говорит мне, для какого объекта нужен контейнер. Есть ли способ разместить 'switch' или' if' и возвращать соответствующий объект каждый раз? – dotNET

+0

Не знаю, что я знаю. Если вы будете использовать Path вместо Ellipse, вы можете привязать его свойство Data к различным геометриям из вашей модели представления. Но, честно говоря, наличие разных элементов представления для разных элементов модели просмотра - именно то, почему есть контейнер товаров. Поэтому вам, вероятно, следует просто сохранить стандартный элемент ItemsControl и выбрать DataTemplates по типу элемента либо с помощью DataTemplates по умолчанию, либо с помощью ItemTemplateSelector. – Clemens