2014-04-15 30 views
0

我有一个ItemsControl,我用它在画布上绘制两组不同的形状。因此,我有两个包含Edge对象和Node对象的ItemsSource在ItemsControl中为特定项目类型设置样式

我有两种不同的DataTemplates为每种类型。但是,我需要设置节点的画布定位,但不是边缘。互联网上有很多关于如何使用单个ItemsSource来做到这一点的例子,但是在我的情况下不能使用多个例子。

我已经像这样破解了它,但是这会在输出窗口中引发很多绑定错误(因为只有Nodes具有Position属性,而不是边缘,因此这是“有效的”)。另外,我想分别为节点和边缘设置ZIndex,这是不可能的。有没有人有什么建议?

<ItemsControl> 
    <ItemsControl.ItemsSource> 
     <MultiBinding> 
      <MultiBinding.Converter> 
       <p:CompositeCollectionConverter/> 
      </MultiBinding.Converter> 
      <Binding Path="Graph.Nodes"/> 
      <Binding Path="Graph.Edges"/> 
     </MultiBinding> 
    </ItemsControl.ItemsSource> 
    <ItemsControl.ItemsPanel> 
     <ItemsPanelTemplate> 
      <Canvas /> 
     </ItemsPanelTemplate> 
    </ItemsControl.ItemsPanel> 
    <ItemsControl.Resources> 
     <DataTemplate DataType="{x:Type model:Edge}"> 
      <Path 
       Stroke="Blue" 
       Data="{Binding Path=EdgeSegments, Converter={StaticResource EdgeSegmentsConverter}}"/> 
     </DataTemplate> 
     <DataTemplate DataType="{x:Type model:Node}"> 
      <Ellipse 
       Width="8" 
       Height="8" 
       Stroke="Black" 
       Fill="Gray"/> 
     </DataTemplate> 
    </ItemsControl.Resources> 
    <ItemsControl.ItemContainerStyle> 
     <Style TargetType="ContentPresenter"> 
      <Setter Property="Canvas.Left"> 
       <Setter.Value> 
        <Binding Path="Position.X"> 
         <Binding.Converter> 
          <p:NodePositionConverter /> 
         </Binding.Converter> 
        </Binding> 
       </Setter.Value> 
      </Setter> 
      <Setter Property="Canvas.Top"> 
       <Setter.Value> 
        <Binding Path="Position.Y"> 
         <Binding.Converter> 
          <p:NodePositionConverter /> 
         </Binding.Converter> 
        </Binding> 
       </Setter.Value> 
      </Setter> 
     </Style> 
    </ItemsControl.ItemContainerStyle> 
</ItemsControl> 

回答

1

为什么不使用ItemContainerStyleSelector?样式添加到ItemsControl.Resources

<Style TargetType="ContentPresenter" x:Key="{x:Type model:Edge}"> 
    <Setter Property="ZIndex"> 
     ... 
    </Setter> 
</Style> 
<Style TargetType="ContentPresenter" x:Key="{x:Type model:Node}"> 
    <Setter Property="ZIndex"> 
     ... 
    </Setter> 
    <Setter Property="Canvas.Top"> 
     ... 
    </Setter> 
    <Setter Property="Canvas.Left"> 
     ... 
    </Setter> 
</Style> 

注意x:Key设置的类型,所以我们可以很容易在风格选择查找由item.GetType()

public override Style SelectStyle(object item, DependencyObject container) { 
     var containerElement = (FrameworkElement)container; 
     var style = containerElement.TryFindResource(item.GetType()) as Style; 
     if (style != null) { 
      return style; 
     } 

     return base.SelectStyle(item, container); 
    } 
+0

我再次重新讨论这个问题,并尝试了解决方案。它运作得非常漂亮,比我的解决方案更优雅,因此已经接受了您的答案。谢谢! – Kazu

0

这是一个有点怪异,你在做什么。我不知道你是否真的需要用这种方式来做到这一点...

你不能合并探微你的两个名单成简单列表?就像这样:

List<AChild> a; 
List<BChild> b; 

List<Mother> ab = a.Concat(b).Cast<Mother>(); 

和之后你查看你可以使用一个TemplateSelector谁可以帮助你选择哪个DataTemplate中是适合的项目。

<ItemsControl ItemTemplateSelector="{StaticResource YourTemplateSelector}" ItemsSource="{Binding ab}"/> 
+0

我不想合并两个集合, 'ItemsSource'绑定完美地工作,所以这不是我的问题。另外,据我所见,'TemplateSelector'与'DataTemplate'一起工作,但我需要在'Canvas'上设置属性,这就是为什么我需要在ItemContainerStyle中有独立的样式。 – Kazu

0

答案由雷切尔在下面的StackOverflow的线程给出:https://stackoverflow.com/a/7931448/970589

所以荣誉给了她。答案摘要如下: 使用转换器检查调用绑定的类型,并根据该类型返回一个值。

相关问题