Используйте другую таблицу данных, привязываясь к разному TreeView selectedItem

Я создал WPF MVVM TreeView, который показывает разные элементы.

BaseElement
- CatA
- SubItemA
- CatB
- SubItemB

В зависимости от класса я хотел бы использовать другой шаблон данных. для каждого типа.

Пока я могу подключиться к выбранному элементу, но не знаю, как управлять различными шаблонами данных.

public class SubItem
{
    public string Type { get; set; }
    public string Name { get; set; }
}


    <StackPanel Grid.Column="2" DataContext="{Binding ElementName=myTreeView, Path=SelectedItem}">
        <TextBox Text="{Binding Parent.Name}" />
        <TextBox Text="{Binding Path=Name, Mode=TwoWay}" />
    </StackPanel>

[Обновление 15 ноября]

           <HierarchicalDataTemplate x:Key="L3Template" ItemsSource="{Binding L4Collection}" ItemTemplate="{StaticResource L4Template}">
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="{Binding Name}" />
                </StackPanel>
            </HierarchicalDataTemplate>

            <HierarchicalDataTemplate x:Key="CategoryTemplate" ItemsSource="{Binding L3Collection}" ItemTemplate="{StaticResource L3Template}">
                <StackPanel>
                    <TextBlock Text="{Binding Name}" />
                </StackPanel>
            </HierarchicalDataTemplate>

            <HierarchicalDataTemplate x:Key="L1Template" ItemsSource="{Binding CategoryCollection}" ItemTemplate="{StaticResource CategoryTemplate}">
                <StackPanel>
                    <TextBlock Text="{Binding Name}" />
                </StackPanel>
            </HierarchicalDataTemplate>

[/ Обновление 15 ноября]


person Stef    schedule 08.11.2012    source источник
comment
Возможный дубликат: stackoverflow.com/q/1152128/577167   -  person Joulukuusi    schedule 09.11.2012


Ответы (3)


Если подэлементы относятся к разным классам, то это довольно просто: добавить datatemplates для каждого класса в раздел ресурсов. Если для подэлементов требуются разные шаблоны в зависимости от значения свойства enum, вам понадобится datatemplateselector. Это немного более громоздко.

person Grafix    schedule 08.11.2012
comment
Спасибо. Пытался использовать для этого значение свойства enum, но селектор datatemplateselector у меня не сработал. Следовательно, я хотел бы немного перекодировать, чтобы использовать разные классы: в этом случае (1) мне нужен родительский класс и подклассы для наблюдаемой коллекции? (2) Как я буду использовать HirachicalDataTemplate для самого TreeView, если у меня разные классы? - person Stef; 14.11.2012
comment
Нет, вам не нужны подклассы для наблюдаемых коллекций. Иерархический шаблон данных почти такой же, как и обычный шаблон данных, он только добавляет возможность указать свойство в вашем объекте, которое будет использоваться для дочерних элементов древовидного элемента. - person Grafix; 15.11.2012
comment
хорошо, я получил этот шаблон HierarchicalDataTemplate [обновление 15 ноября], который строит красивое дерево для всех уровней. Если бы CatX был одним классом с разными именами, CatX должен был бы содержать разные классы объектов. Я мог бы добавить две observableCollections двух разных классов. Но я не вижу, где я делаю дифференциацию / переключение в XAML / HierarchicalDataTemplate, поскольку я, вероятно, могу сделать только один оператор ItemTemplate = {StaticResource L3Template} ?! - person Stef; 15.11.2012
comment
Я понимаю вашу точку зрения. В этом случае вы не устанавливаете ItemTemplate, но вы добавляете шаблоны данных в раздел ресурсов вашего древовидного представления (например,). Вам нужно будет заполнить TargetType и не использовать никаких ключей. Затем WPF применяет шаблон в зависимости от типа класса. Позже я добавлю пример кода. - person Grafix; 19.11.2012
comment
Со вторым ответом теперь это хорошо работает! Я заменил StackPanel на ContentPresenter, как здесь: stackoverflow.com/questions/1152128/, тогда он отлично работает. - person Stef; 20.11.2012

Предполагая, что вы назвали свои классы L1Class, L3Class en Category, а local указывает на пространство имен этих классов:

    <TreeView ...>
        <TreeView.Resources>
                <HierarchicalDataTemplate DataType="{x:Type local:L3Class}" ItemsSource="{Binding L4Collection}" >
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="{Binding Name}" />
                    </StackPanel>
                </HierarchicalDataTemplate>

                <HierarchicalDataTemplate DataType="{x:Type local:Category}" ItemsSource="{Binding L3Collection}" >
                    <StackPanel>
                        <TextBlock Text="{Binding Name}" />
                    </StackPanel>
                </HierarchicalDataTemplate>

                <HierarchicalDataTemplate DataType="{x:Type local:L1Class}" ItemsSource="{Binding CategoryCollection}" >
                    <StackPanel>
                        <TextBlock Text="{Binding Name}" />
                    </StackPanel>
                </HierarchicalDataTemplate>
            </TreeView.Resources>
    </TreeView>

Обратите внимание на использование неявных шаблонов данных (без ключей, но DataType!) В разделе ресурсов.

person Grafix    schedule 19.11.2012
comment
Здорово! Это хорошо работает. Вы действительно раскрыли тайну TreeViews и HirachicalDataTemplates! Большое спасибо. Я подключил его к своим ViewModel, например DataType = {x: Type local: CategoryViewModel}. и добавил локальный оператор xmlns: local = clr-namespace: MyApplication.ViewModel. Тогда это хорошо работает. - person Stef; 20.11.2012

На всякий случай кому-то поможет:

        <ContentPresenter Grid.Column="2" Content="{Binding ElementName=myTreeView, Path=SelectedItem}">
            <ContentPresenter.Resources>
                <DataTemplate DataType="{x:Type local:L1ViewModel}">
                    <StackPanel>
                        <TextBlock Text="{Binding Name}" />
                    </StackPanel>
                </DataTemplate>
                <DataTemplate DataType="{x:Type local:CategoryViewModel}">
                    <StackPanel>
                        <TextBlock Text="{Binding Name}" />
                    </StackPanel>
                </DataTemplate>

                <DataTemplate DataType="{x:Type local:L3ViewModel}">
                    <StackPanel>
                        <TextBlock Text="{Binding Name}" />
                    </StackPanel>
                </DataTemplate>

                <DataTemplate DataType="{x:Type local:L4ViewModel}">
                    <StackPanel>
                         <TextBox Text="{Binding Parent.Name}" />
                        <TextBlock Text="{Binding Name}" />
                    </StackPanel>
                </DataTemplate>
            </ContentPresenter.Resources>
          </ContentPresenter>
person Stef    schedule 20.11.2012