Динамическое изменение коллекции Itemsource в HierarchialDataTemplate TreeView

TreeView должен рекурсивно заполняться другой коллекцией.

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

Я попытался создать Observable Collection класса ViewModelBase, который фактически распространяется на все остальные классы ViewModel, думая, что я могу использовать экземпляр ViewModel любого типа для Observable Collection. Но это будет работать, когда мне не придется работать с двумя разными коллекциями одновременно.

<HierarchicalDataTemplate DataType="{x:Type VM:ViewModelBase}" ItemsSource="{Binding SecondViewModelCollection}">
                        <StackPanel Orientation="Horizontal" >
                            <Image Source="../resources/New_Package.png" Width="15" Height="15"/>
                            <TextBlock Text="{Binding Header}" Loaded="Project_Loaded"></TextBlock>
                        </StackPanel>
                        <HierarchicalDataTemplate.ItemTemplate>
                            <HierarchicalDataTemplate DataType="{x:Type VM:ViewModelBase}" ItemsSource="{Binding ThirdViewModelCollection}">
                                <StackPanel Orientation="Horizontal" >
                                    <Image Source="../resources/New_Package.png" Width="15" Height="15"/>
                                    <TextBlock Text="{Binding Header}"></TextBlock>
                                </StackPanel>
                                <HierarchicalDataTemplate.ItemTemplate>
                                    <HierarchicalDataTemplate DataType="{x:Type VM:ViewModelBase}" ItemsSource="{Binding FourthViewModelBaseCollection}">
                                        <StackPanel Orientation="Horizontal">
                                            <Image Source="../resources/New_Package.png" Width="15" Height="15"/>
                                            <TextBlock Text="{Binding Header}"  MouseDown="TextBlock_MouseUp" 
                                                       Loaded="TextBlock_Loaded" Focusable="True"/>
                                            <TextBox LostFocus="TextBox_LostFocus" Visibility="Collapsed" MouseEnter="TextBox_MouseEnter"/>
                                        </StackPanel>
                                        <HierarchicalDataTemplate.ItemTemplate>
                                            <HierarchicalDataTemplate DataType="{x:Type VM:ViewModelBase}" ItemsSource="{Binding FeatureViewModelCollection}">
                                                <StackPanel Orientation="Horizontal">
                                                    <Image Source="../resources/file.png" Width="15" Height="15"/>
                                                    <TextBlock Text="{Binding Header}"/>
                                                </StackPanel>
                                                <HierarchicalDataTemplate.ItemTemplate>
                                                    <HierarchicalDataTemplate DataType="{x:Type VM:ViewModelBase}" ItemsSource="{Binding Usecaselist}">
                                                        <StackPanel>
                                                            <TextBlock Text="{Binding Header}"  MouseDown="TextBlock_MouseUp" 
                                                                       Loaded="TextBlock_Loaded" Focusable="True" />

                                                            <TextBox LostFocus="TextBox_LostFocus" Visibility="Collapsed" MouseEnter="TextBox_MouseEnter"/>

                                                        </StackPanel>
                                                        <HierarchicalDataTemplate.ItemTemplate>
                                                            <DataTemplate DataType="{x:Type VM:ViewModelBase}">
                                                                <StackPanel >
                                                                    <TextBlock Text="{Binding Header}" MouseDown="TextBlock_MouseUp"  
                                                                               Loaded="TextBlock_Loaded"  Focusable="True" />

                                                                    <TextBox 
                                                                             LostFocus="TextBox_LostFocus" Visibility="Collapsed"
                                                                             MouseEnter="TextBox_MouseEnter" >
                                                                    </TextBox>
                                                                </StackPanel>
                                                            </DataTemplate>
                                                        </HierarchicalDataTemplate.ItemTemplate>

                                                    </HierarchicalDataTemplate>
                                                </HierarchicalDataTemplate.ItemTemplate>
                                            </HierarchicalDataTemplate>
                                        </HierarchicalDataTemplate.ItemTemplate>
                                    </HierarchicalDataTemplate>
                                </HierarchicalDataTemplate.ItemTemplate>
                            </HierarchicalDataTemplate>
                        </HierarchicalDataTemplate.ItemTemplate>
public class ViewModelBase : INotifyPropertyChanged
{
     public event PropertyChangedEventHandler PropertyChanged;

     protected void OnPropertyChanged(String propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
}
> Level 1
      > Level 2.1 (Diff class with diff. collection)
         > Level 3.1 (Diff from other 3.1)
           > Level 4.1
           > Level 4.2
         > Level 3.2 (Diff from other 3.2)
         > Level 3.3 (Diff from other 3.3)
      > Level 2.2 (Diff class with diff. collection)
         > Level 3.1 (Diff from other 3.1)
         > Level 3.2 (Diff from other 3.2)
      > Level 2.3 (Diff class with diff. collection)
         > Level 3.1 (Diff from other 3.1)
         > Level 3.2 (Diff from other 3.2)

Теперь объекты ThirdViewModelCollection имеют два типа, не только тип данных/объект отличается, но и коллекция внутри них будет отличаться отсюда.


person User1312    schedule 09.09.2019    source источник
comment
см. этот stackoverflow.com/questions/56703365/   -  person Sorush    schedule 09.09.2019


Ответы (1)


Требуется, чтобы все типы данных расширяли общий базовый тип (например, ViewModelBase). Затем вы можете (и должны) смешивать типы, содержащиеся в коллекции этого общего базового типа (например, ObservableCollection<ViewModeBase>), чтобы каждый узел имел ровно одну коллекцию, содержащую дочерние элементы, которые расширяют базовый тип общего дерева.
Затем используйте DataTemplateSelector чтобы вернуть соответствующий DataTemplate для типа узла.

Таким образом, TreeView генерируется динамически независимо от ширины или высоты, пока существует DataTemplate для каждого возможного типа узла.

Динамический TreeView

<TreeView ItemsSource="{Binding Items}"
          ItemTemplateSelector="{DynamicResource DataTemplateSelector}">
  <TreeView.Resources>
    <local:DataTemplateSelector x:Key="DataTemplateSelector" />

<!-- The DataTemplates for each node type -->   
    <HierarchicalDataTemplate x:Key="FirstDataTemplate"
                              DataType="FirstViewModel"
                              ItemsSource="{Binding ChildItems}">
      <TextBlock Text="{Binding Name}" />
    </HierarchicalDataTemplate>

    <HierarchicalDataTemplate x:Key="SecondDataTemplate"
                              DataType="SecondViewModel"
                              ItemsSource="{Binding ChildItems}">
      <TextBlock Text="{Binding Name}" />
    </HierarchicalDataTemplate>

    <HierarchicalDataTemplate x:Key="ThirdDataTemplate"
                              DataType="ThirdViewModel"
                              ItemsSource="{Binding ChildItems}">
      <TextBlock Text="{Binding Name}" />
    </HierarchicalDataTemplate>

    <HierarchicalDataTemplate x:Key="IndFeatureDataTemplate"
                              DataType="IndFeatureViewModel"
                              ItemsSource="{Binding ChildItems}">
      <TextBlock Text="{Binding Name}" />
    </HierarchicalDataTemplate>

    <DataTemplate x:Key="IndUsecaseDataTemplate"
                  DataType="IndUsecaseViewModel">
      <TextBlock Text="{Binding Name}" />
    </DataTemplate>
  </TreeView.Resources>
</TreeView>

Селектор DataTemplateSelector для TreeView

class DataTemplateSelector : System.Windows.Controls.DataTemplateSelector
{
  public override DataTemplate
    SelectTemplate(object item, DependencyObject container)
  {
    FrameworkElement element = container as FrameworkElement;

     return item is FirstViewModel 
       ? element.FindResource("FirstDataTemplate") as DataTemplate 
       : item is SecondViewModel 
         ? element.FindResource("SecondDataTemplate") as DataTemplate
         : item is ThirdViewModel 
           ? element.FindResource("ThirdDataTemplate") as DataTemplate
           : item is IndFeatureViewModel
             ? element.FindResource("IndFeatureDataTemplate") as DataTemplate
             : element.FindResource("IndUsecaseDataTemplate") as DataTemplate;
  }
}

Общий базовый тип

public abstract class ViewModelbase
{
  public ObservableCollection<ViewModelBase> ChildItems { get;set; }   
  public string Name { get;set; }    
}

Расширенный тип

public class FirstViewModel : ViewModelbase
{
  public FirstViewModel() 
  {
    // Create a collection with mixed types all derived from ViewModellBase
    this.ChildItems = new ObservableCollection<ViewModeLBase>() 
    { 
      new SecondViewModel(), 
      new ThirdViewModel(),
      new IndUsecaseViewModel()
    };
  }

  public ObservableCollection<ViewModelBase> ChildItems { get;set; }    
}
person BionicCode    schedule 09.09.2019
comment
Спасибо за ответ. В этом ответе показано, как решить проблему разных типов данных, и я принял то же самое в своем проекте. Но моя проблема связана с классами с другой коллекцией, а ViewModelBase не является абстрактным классом в моем случае, поскольку он используется для реализации INotifyPropertyChanged. Я обновил вопрос. Пожалуйста, дайте мне знать, если я что-то упустил. - person User1312; 10.09.2019