代码之家  ›  专栏  ›  技术社区  ›  user8574993

如何以分层方式将ObservableCollection绑定到TreeView?

  •  1
  • user8574993  · 技术社区  · 8 年前

    Technik

    public class Technik
    {
        public bool checkedTe { get; set; }
    
        public int TechnikID { get; set; }
    
        public string anlagengruppe { get; set; }
    
        public string techniktyp { get; set; }
    
        public string anlage { get; set; }
    
        public string bemerkung { get; set; }
    }
    

    DataTable 有216行,每行进入一个 特赫尼克 添加到我的 ObservableCollection<Technik> 例如:

    foreach (DataRow dr in dtTechnik.Rows)
    {
         Technik technik = new Technik();
    
         technik.checkedTe = (bool)dr.ItemArray[0];
         technik.TechnikID = (int)dr.ItemArray[1];
         technik.anlagengruppe = (string)dr.ItemArray[2];
         technik.techniktyp = (string)dr.ItemArray[3];
         technik.anlage = (string)dr.ItemArray[4];
         technik.bemerkung = (string)dr.ItemArray[5];
    
         TechnikCollection.Add(technik);
    }
    

    ObservableCollection 例如:

    * anlagengruppe
        * techniktyp
              *anlage
                 * TechnikID
    

    现在我一事无成,也许你们可以帮我。 实际上,我的树视图如下所示:

    <TreeView x:Name="treeView" HorizontalAlignment="Left" Height="850" Margin="10,0,0,0" VerticalAlignment="Top" Width="464" 
              ScrollViewer.CanContentScroll="True" ScrollViewer.VerticalScrollBarVisibility="Visible" ItemsSource="{Binding TechnicTable}">
        <TreeView.ItemTemplate>
            <HierarchicalDataTemplate ItemsSource="{Binding TechnicTable}">
                <TextBlock  Text="{Binding Path=anlagengruppe}" />
                <HierarchicalDataTemplate.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding techniktyp}" />
                    </DataTemplate>
                </HierarchicalDataTemplate.ItemTemplate>
            </HierarchicalDataTemplate>
        </TreeView.ItemTemplate>
    </TreeView>
    

    编辑: ItemsSource 不是正确的集合,这是正确的集合,还有一些代码需要我更改集合。

    1 回复  |  直到 8 年前
        1
  •  0
  •   Peter Duniho    8 年前

    我对这个设计持怀疑态度。为什么您认为将单个对象及其属性值呈现为该对象具有某种层次结构对用户有用?

    如果你只是想强加一些 结构,无需使用 TreeView

    class TableItem
    {
        public string Property1 { get; set; }
        public string Property2 { get; set; }
        public string Property3 { get; set; }
    
        public TableItem() { }
    
        public TableItem(string property1, string property2, string property3)
        {
            Property1 = property1;
            Property2 = property2;
            Property3 = property3;
        }
    }
    
    class ViewModel
    {
        public ObservableCollection<TableItem> TableItems { get; } = new ObservableCollection<TableItem>();
    }
    
    <Window x:Class="TestSO46300831HiearchicalObservable.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:l="clr-namespace:TestSO46300831HiearchicalObservable"
            mc:Ignorable="d"
            Title="MainWindow" Height="350" Width="525">
      <Window.DataContext>
        <l:ViewModel>
          <l:ViewModel.TableItems>
            <l:TableItem Property1="Item #1, property #1"
                         Property2="Item #1, property #2"
                         Property3="Item #1, property #3"/>
            <l:TableItem Property1="Item #2, property #1"
                         Property2="Item #2, property #2"
                         Property3="Item #2, property #3"/>
            <l:TableItem Property1="Item #3, property #1"
                         Property2="Item #3, property #2"
                         Property3="Item #3, property #3"/>
          </l:ViewModel.TableItems>
        </l:ViewModel>
      </Window.DataContext>
    
      <Window.Resources>
        <DataTemplate DataType="{x:Type l:TableItem}">
          <StackPanel>
            <TextBlock Text="{Binding Property1}"/>
            <TextBlock Text="{Binding Property1}" Margin="10,0,0,0"/>
            <TextBlock Text="{Binding Property1}" Margin="20,0,0,0"/>
          </StackPanel>
        </DataTemplate>
      </Window.Resources>
    
      <StackPanel>
        <ListBox ItemsSource="{Binding TableItems}"/>
      </StackPanel>
    </Window>
    

    也就是说,如果你 使用 树状视图 INotifyCollectionChanged ObservableCollection<T> 并追踪原始收藏。需要中间集合,以便可以将项目从原始的单个对象项目转换为可与 班例如:

    class HierarchicalTableItem
    {
        public string Text { get; }
        public IReadOnlyList<HierarchicalTableItem> Items { get; }
    
        public HierarchicalTableItem(string text, HierarchicalTableItem child = null)
        {
            Text = text;
            Items = child != null ? new[] { child } : null;
        }
    }
    
    class ViewModel
    {
        public ICommand AddCommand { get; }
        public ICommand InsertCommand { get; }
        public ICommand RemoveCommand { get; }
    
        public int Index { get; set; }
    
        public ObservableCollection<TableItem> TableItems { get; } = new ObservableCollection<TableItem>();
    
        public ViewModel()
        {
            AddCommand = new DelegateCommand(() => TableItems.Add(_CreateTableItem()));
            InsertCommand = new DelegateCommand(() => TableItems.Insert(Index, _CreateTableItem()));
            RemoveCommand = new DelegateCommand(() => TableItems.RemoveAt(Index));
        }
    
        private int _itemNumber;
    
        private TableItem _CreateTableItem()
        {
            _itemNumber = (_itemNumber < TableItems.Count ? TableItems.Count : _itemNumber) + 1;
    
            return new TableItem(
                $"Item #{_itemNumber}, property #1",
                $"Item #{_itemNumber}, property #2",
                $"Item #{_itemNumber}, property #3");
        }
    }
    
    class ConvertingObservableCollection<T> : ObservableCollection<object>
    {
        private readonly IValueConverter _converter;
        private readonly ObservableCollection<T> _collection;
    
        public ConvertingObservableCollection(IValueConverter converter, ObservableCollection<T> collection)
        {
            _converter = converter;
            _collection = collection;
            _ResetItems();
            _collection.CollectionChanged += _OnCollectionChanged;
        }
    
        private void _OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            switch (e.Action)
            {
                case NotifyCollectionChangedAction.Add:
                    _AddItems(e);
                    break;
                case NotifyCollectionChangedAction.Move:
                    _RemoveItems(e);
                    _AddItems(e);
                    break;
                case NotifyCollectionChangedAction.Remove:
                    _RemoveItems(e);
                    break;
                case NotifyCollectionChangedAction.Replace:
                    _ReplaceItems(e);
                    break;
                case NotifyCollectionChangedAction.Reset:
                    _ResetItems();
                    break;
            }
        }
    
        private void _ReplaceItems(NotifyCollectionChangedEventArgs e)
        {
            for (int i = 0; i < e.NewItems.Count; i++)
            {
                this[i] = _Convert(e.NewItems[i]);
            }
        }
    
        private void _AddItems(NotifyCollectionChangedEventArgs e)
        {
            for (int i = 0; i < e.NewItems.Count; i++)
            {
                Insert(i + e.NewStartingIndex, _Convert(e.NewItems[i]));
            }
        }
    
        private void _RemoveItems(NotifyCollectionChangedEventArgs e)
        {
            for (int i = e.OldItems.Count - 1; i >= 0; i--)
            {
                RemoveAt(i + e.OldStartingIndex);
            }
        }
    
        private void _ResetItems()
        {
            Clear();
            foreach (T t in _collection)
            {
                Add(_Convert(t));
            }
        }
    
        private object _Convert(object value)
        {
            return _converter.Convert(value, typeof(T), null, null);
        }
    }
    
    class TableItemHierarchicalConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            TableItem tableItem = value as TableItem;
    
            if (tableItem == null)
            {
                return Binding.DoNothing;
            }
    
            return new HierarchicalTableItem(tableItem.Property1,
                        new HierarchicalTableItem(tableItem.Property2,
                            new HierarchicalTableItem(tableItem.Property3)));
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
    
    class ConvertingCollectionConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            IValueConverter converter = parameter as IValueConverter;
    
            if (converter == null || value == null ||
                value.GetType().GetGenericTypeDefinition() != typeof(ObservableCollection<>))
            {
                return Binding.DoNothing;
            }
    
            Type resultType = typeof(ConvertingObservableCollection<>).MakeGenericType(value.GetType().GenericTypeArguments);
    
            return Activator.CreateInstance(resultType, converter, value);
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
    
    <Window x:Class="TestSO46300831HiearchicalObservable.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:l="clr-namespace:TestSO46300831HiearchicalObservable"
            mc:Ignorable="d"
            Title="MainWindow" Height="350" Width="525">
      <Window.DataContext>
        <l:ViewModel>
          <l:ViewModel.TableItems>
            <l:TableItem Property1="Item #1, property #1"
                         Property2="Item #1, property #2"
                         Property3="Item #1, property #3"/>
            <l:TableItem Property1="Item #2, property #1"
                         Property2="Item #2, property #2"
                         Property3="Item #2, property #3"/>
            <l:TableItem Property1="Item #3, property #1"
                         Property2="Item #3, property #2"
                         Property3="Item #3, property #3"/>
          </l:ViewModel.TableItems>
        </l:ViewModel>
      </Window.DataContext>
    
      <Window.Resources>
        <l:ConvertingCollectionConverter x:Key="convertingCollectionConverter1"/>
        <l:TableItemHierarchicalConverter x:Key="tableItemConverter1"/>
      </Window.Resources>
    
      <ScrollViewer>
        <StackPanel>
          <UniformGrid Columns="4">
            <Button Content="Add" Command="{Binding AddCommand}"/>
            <Button Content="Insert" Command="{Binding InsertCommand}"/>
            <Button Content="Remove" Command="{Binding RemoveCommand}"/>
            <TextBox Text="{Binding Index}"/>
          </UniformGrid>
          <TreeView ItemsSource="{Binding TableItems,
                  Converter={StaticResource convertingCollectionConverter1},
                  ConverterParameter={StaticResource tableItemConverter1}}">
            <TreeView.ItemTemplate>
              <HierarchicalDataTemplate ItemsSource="{Binding Items}">
                <TextBlock Text="{Binding Text}"/>
              </HierarchicalDataTemplate>
            </TreeView.ItemTemplate>
          </TreeView>
        </StackPanel>
      </ScrollViewer>
    </Window>
    

    • ConvertingObservableCollection<T> -这可以查看原始收藏并根据原始收藏的当前状态显示转换的项目。
    • ConvertingCollectionConverter -这会将原始集合转换为 ConvertingObservableCollection<T> 对象以绑定到 树状视图
    • TableItemHierarchicalConverter 树状视图

    当然,还有一个简单的容器类 HierarchicalTableItem 用于表示每个表项的层次结构。

    归根结底,要记住的关键是 树状视图 必须 HierarchicalDataTemplate 元素可用于定义如何显示 每个级别 在树上。这意味着单个数据项必须具有可用于 ItemsSource 模板本身是相同类型数据项的某种类型的集合。