Вопрос по шаблону иерархических данных в дереве WPF - PullRequest
0 голосов
/ 01 февраля 2011

У меня есть дерево WPF, которое должно показать некоторые узлы. Допустим, у меня есть 2 типа сущностей, EntityA и EntityB. Оба эти объекта реализуют общий интерфейс IEntity. Теперь EntityA будет иметь коллекцию элементов EntityB, а также элементов EntityA. Как я могу показать это через HierarchicalDataTemplate?

Я выставляю ObservableCollection () с именем «DisplayItems» в моей виртуальной машине, которая будет содержать элементы типа EntityA.

И EnittyA, и EntityB будут иметь другую коллекцию ObservableCollection, которая называется ItemCollection. Для 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 голосов
/ 01 февраля 2011

Полагаю, 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>
0 голосов
/ 01 февраля 2011

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