关于WPF树中分层数据模板的问题

时间:2011-02-01 03:58:42

标签: wpf

我有一个需要显示一些节点的WPF树。假设我有两种类型的实体,EntityA和EntityB。这两个实体都实现了一个公共接口IEntity。现在,EntityA将拥有EntityB元素和EntityA元素的集合。如何通过HierarchicalDataTemplate显示此内容?

我在我的VM中公开了一个名为“DisplayItems”的ObservableCollection(),它将包含EntityA类型的元素。

EnittyA和EntityB都会有另一个名为“ItemCollection”的ObservableCollection。对于EntityA,ItemCollection列表理想情况下应包含EntityA和EntityB类型的实体。

当前的HierarchicalDataTemplate和我使用的XAML如下:

 <HierarchicalDataTemplate ItemsSource="{Binding Path=ItemCollection}" DataType="{x:Type Entities:EntityB}">
      <Grid>
        <StackPanel Orientation="Horizontal" x:Name="compositeCT">
          <Image Source="/Images/EntityB.png" Width="15" Height="15"/>
          <Label Foreground="Blue" Content="{Binding Path=Name}"/>
          <Label Foreground="Black" Content=" = "/>
          <Label Foreground="Blue" Content="{Binding Path=CompositeLabel}"/>
        </StackPanel>
        <StackPanel Orientation="Horizontal" x:Name="nCompositeCT">
          <Image Source="/Images/EntityB.png" Width="15" Height="15"/>
          <TextBlock Foreground="Blue" Text="{Binding Path=Name}"/>
        </StackPanel>
 <HierarchicalDataTemplate.ItemTemplate>
        <DataTemplate>
          <TextBlock Foreground="Green" Text="{Binding}"/>
        </DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>

 <HierarchicalDataTemplate ItemsSource="{Binding Path=ItemCollection}" DataType="{x:Type Entities:EntityA}">
      <StackPanel Orientation="Horizontal" >
        <Image Source="/Images/ElementA.png" Margin="3" Width="15" Height="15" Focusable="False"/>
        <TextBlock Foreground="Red" Text="{Binding Path = Name}" Focusable="False"/>
      </StackPanel>
    </HierarchicalDataTemplate>

<TreeView x:Name="tvMyTree"
            ItemsSource="{Binding DisplayItems}"
            AllowDrop="True"         
            VirtualizingStackPanel.IsVirtualizing="True" 
            VirtualizingStackPanel.VirtualizationMode="Recycling" 
            ScrollViewer.IsDeferredScrollingEnabled="True"
            Margin="5"
            TreeViewItem.Expanded="OnTreeViewItemExpanded"
            TreeViewItem.Selected="OnTreeViewItemSelected" 
         />

2 个答案:

答案 0 :(得分:0)

您可以定义两个HierarchicalDataTemplates。在TextBlock的位置,您可以根据EntityA和EntityB的其他属性放置所需的任何复杂可视化

        <HierarchicalDataTemplate  DataType="{x:Type local:EnittyA}" ItemsSource="{Binding ItemCollection}" >
            <TextBlock Text="{Binding Name}"/>
        </HierarchicalDataTemplate>
        <HierarchicalDataTemplate  DataType="{x:Type local:EnittyB}" ItemsSource="{Binding ItemCollection}" >
            <TextBlock Text="{Binding Name}"/>
        </HierarchicalDataTemplate>

答案 1 :(得分:0)

我认为ItemTemplateSelector非常适合您的要求。 ItemTemplateSelector是继承的,因此您不应该关心模板的端点接收器。 Receiver(项容器)只是寻址到选择器,最后一个根据DataType返回正确的模板:

public class LayoutItemTemplateSelectorItem
{
    public Type TargetType
    {
        get;
        set;
    }
    public DataTemplate Template
    {
        get;
        set;
    }
}
[ContentProperty("Items")]
public class LayoutItemTemplateSelector : DataTemplateSelector
{
    public LayoutItemTemplateSelector()
    {
        this.Items = new Collection<LayoutItemTemplateSelectorItem>();
    }
    public Collection<LayoutItemTemplateSelectorItem> Items
    {
        get;
        private set;
    }
    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        var component = (LayoutItem)item;
        var typeToSearch = component.GetType();

        var foundItem = this.Items
            .Where(i => i.TargetType == typeToSearch)
            .FirstOrDefault();

        if (foundItem != null)
        {
            return foundItem.Template;
        }

        throw new Exception(string.Format(Properties.Resources.AppropriateTemplateNotFound, typeToSearch.FullName));
    }
}

XAML中的用法:

<UserControl ...>
    <UserControl.Resources>
        <ResourceDictionary>

            <HierarchicalDataTemplate  x:Key="EntityBTemplate" 
                                       ItemsSource="{Binding Path=ItemCollection}"
                                       DataType="{x:Type Entities:EntityB}">
                ...
            </HierarchicalDataTemplate>

            <HierarchicalDataTemplate x:Key="EntityATemplate" 
                                      ItemsSource="{Binding Path=ItemCollection}"
                                      DataType="{x:Type Entities:EntityA}">
                ...
            </HierarchicalDataTemplate>

            <LayoutItemTemplateSelector x:Key="TemplateSelector">
                <LayoutItemTemplateSelectorItem TargetType="{x:Type EntityA}"
                                                Template="{StaticResource EntityATemplate}"/>
                <LayoutItemTemplateSelectorItem TargetType="{x:Type EntityB}"
                                                Template="{StaticResource EntityBTemplate}"/>
            </LayoutItemTemplateSelector>
        </ResourceDictionary>
    </UserControl.Resources>
<Grid>
    <TreeView ItemsSource="{Binding DisplayItems}"
              ItemTemplateSelector="{StaticResource TemplateSelector}"/>
</Grid>
</UserControl>