Изменить шаблон TreeViewItem, когда IsSelected и два типа, используя в TreeView - PullRequest
4 голосов
/ 03 февраля 2012

В моем TreeView я использую два разных класса для привязки. Например, у меня есть группа, которая может иметь ChildGroup и может иметь элементы. Пример кода этого класса:

using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace WpfApplication1
{
public class Group
{
    public Group(string name)
    {
        Name = name;
        items = new ObservableCollection<Item>();
        groups = new ObservableCollection<Group>();
    }
    public string Name { get;
        set;
    }

    private ObservableCollection<Item> items;
    private ObservableCollection<Group> groups;

    public ObservableCollection<Item> Items
    {
        get { return items; }
    }


    public ObservableCollection<Group> Groups
    {
        get { return groups; }
    }

    public IEnumerable<object> AllItems
    {
        get
        {
            foreach (var group in groups)
            {
                yield return group;
            }
            foreach (var item in items)
            {
                yield return item;
            }
        }
    }

}

public class Item
{
    public Item(string name)
    {
        ItemName = name;
    }

    public string ItemName
    {
        get;
        set;
    } 
}
}

Чтобы привязать его к TreeView, я использую следующий шаблон

<Grid>
    <TreeView Name="treeView">
        <TreeView.Resources>
            <HierarchicalDataTemplate DataType="{x:Type WpfApplication1:Group}"
                                      ItemsSource="{Binding AllItems}">
                <TextBlock Text="{Binding Name}"/>
            </HierarchicalDataTemplate>
            <DataTemplate DataType="{x:Type WpfApplication1:Item}">
                <TextBlock Text="{Binding ItemName}" FontStyle="Italic"/>
            </DataTemplate>
        </TreeView.Resources>
    </TreeView>
</Grid>

Это легко.

Проблема в том, что мне нужно изменить ItemTemplate, когда выбрано. И мне нужно изменить только тогда выбранный класс предметов.

Я могу это сделать, если для связывания используется только один класс. Также легко использовать Style и Trigger, например:

<TreeView Name="treeView1" Grid.Column="1">
        <TreeView.Resources>
            <HierarchicalDataTemplate DataType="{x:Type WpfApplication1:Group}"
                                      ItemsSource="{Binding AllItems}"
                                      x:Key="groupTemplate">
                <TextBlock Text="{Binding Name}"/>
            </HierarchicalDataTemplate>
            <HierarchicalDataTemplate DataType="{x:Type WpfApplication1:Group}"
                                      ItemsSource="{Binding AllItems}"
                                      x:Key="selectedGroupTemplate">
                <TextBlock Text="{Binding Name}" FontStyle="Italic" FontWeight="Bold" FontSize="14"/>
            </HierarchicalDataTemplate>
        </TreeView.Resources>

        <TreeView.ItemContainerStyle>
            <Style TargetType="{x:Type TreeViewItem}">
                <Setter Property="HeaderTemplate" Value="{StaticResource groupTemplate}"/>
                <Style.Triggers>
                    <Trigger Property="IsSelected" Value="True">
                        <Setter Property="HeaderTemplate" Value="{StaticResource selectedGroupTemplate}"/>
                    </Trigger>
                </Style.Triggers>
            </Style>
        </TreeView.ItemContainerStyle>
    </TreeView>

Но у меня проблема с мультиклассовым связыванием.

Как изменить шаблон SelectedItem, а затем использовать мультиклассовую привязку? Есть идеи?

Мой код за образцом:

using System.Collections.ObjectModel;
using System.Windows;

namespace WpfApplication1
{
/// <summary>
/// Interaction logic for Window2.xaml
/// </summary>
public partial class Window2 : Window
{
    private ObservableCollection<Group> _groups;
    public ObservableCollection<Group> Groups
    {
        get { return _groups; }
    }

    public Window2()
    {
        InitializeComponent();

        InitGroups();

        treeView.ItemsSource = _groups;
        treeView1.ItemsSource = _groups;
    }

    private void InitGroups()
    {
        _groups = new ObservableCollection<Group>();

        Group group1 = new Group("Group1");
        group1.Groups.Add(new Group("Group1.1"));
        group1.Groups.Add(new Group("Group1.2"));
        group1.Groups.Add(new Group("Group1.3"));

        group1.Items.Add(new Item("Item1.1"));
        group1.Items.Add(new Item("Item1.2"));

        group1.Groups[1].Items.Add(new Item("Item1.2.1"));
        group1.Groups[1].Items.Add(new Item("Item1.2.2"));


        _groups.Add(group1);

        Group group2 = new Group("Group2");
        group2.Groups.Add(new Group("Group2.1"));
        group2.Groups.Add(new Group("Group2.2"));

        group2.Items.Add(new Item("Item2.1"));
        group2.Groups[0].Items.Add(new Item("Item2.1.1"));
        group2.Groups[0].Items.Add(new Item("Item2.1.1"));

        _groups.Add(group2);
    }
}
}

Результат Result

Теперь я думаю использовать TreeView.HeaderTemplateSelector, но может существовать способ использовать только xaml.

Спасибо.

1 Ответ

4 голосов
/ 06 февраля 2012

Есть несколько способов достичь желаемого результата. Если вы уверены, что ваш DataTemplate будет использоваться только в TreeViewItem объектах, тогда проще всего просто привязать непосредственно к свойству TreeViewItem.IsSelected и затем отреагировать на изменение в DataTemplate:

    <DataTemplate DataType="{x:Type WpfApplication1:Item}">
        <TextBlock Text="{Binding ItemName}">
            <TextBlock.Style>
                <Style>
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding IsSelected, RelativeSource=
{RelativeSource FindAncestor, AncestorType={x:Type TreeViewItem}}, FallbackValue=False}" 
Value="True">
                            <Setter Property="TextBlock.FontStyle" Value="Italic" />
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </TextBlock.Style>
        </TextBlock>
    </DataTemplate> 
...