私はこのデザインに懐疑的です。単一のオブジェクトとそのプロパティ値がそのオブジェクトに階層的な構造を持っているかのように提示することは、ユーザーにとって便利で役立ちます。
視覚的なの構造をユーザーインターフェイスに課すことは、TreeView
を使わずに簡単に行うことができます。例:あなたはは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>
を継承し、元のコレクションを追跡するだけで簡単に実行できます)。中間コレクションが必要なので、元の単一オブジェクトアイテムからTreeView
クラスで使用できる階層アイテムタイプにアイテムを変換できます。例:
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>
この選択肢は3つの主要なクラスに依存している:これは、元のコレクションを見て、その元のコレクションの現在の状態に応じて変換された項目を提示する作業を行う
ConvertingObservableCollection<T>
—。
- —
TreeView
にバインドする目的で、元のコレクションをConvertingObservableCollection<T>
オブジェクトに変換します。
TableItemHierarchicalConverter
—これは、個々の元のアイテムオブジェクトをTreeView
の表示に適したオブジェクトの階層に変換します。
もちろん、各テーブル項目の階層を表すために使用される単純なコンテナクラスHierarchicalTableItem
もあります。
最終的に、覚えておくべきキーがTreeView
のために、あなたは単一HierarchicalDataTemplate
要素がツリーの各レベルを提示する方法を定義するために使用することができるように、再帰的な性質を持っているアイテムを、提示しなければならないということです。つまり、1つのデータ項目にテンプレートのItemsSource
に使用できるいくつかのプロパティが必要です。テンプレート自体は同じタイプのデータ項目のコレクションです。
'HierarchicalDataTemplate'は' Technik'モデルには対応していません。そのクラスには 'TechnicTable'コレクションはありませんが、そのプロパティにバインドしようとしています。 – dymanoid
EDITの最初のおかげで...私の問題は、Technik Modelのプロパティを正しくバインドする方法を知らないということです。これはすべて試行錯誤しています。どのようにこれらのプロパティを正しくバインドするのですか? – user8574993