WPF привязка двухуровневых структурированных данных без прямых ссылок
Мне нужно представить двухуровневые структурированные данные MVVM. Если бы данные были:
public class ParentEntity
{
public ObservableCollection<ChildEntity> ChildsEntities { get; set; } = new ObservableCollection<ChildEntity>();
public string Name { get; set; }
}
public class ChildEntity
{
public string Name { get; set; }
public int Value { get; set; }
}
тогда я бы создал привязку с TreeView:
<TreeView x:Name="treeView">
<TreeView.Resources>
<!--Template for ParentEntity-->
<HierarchicalDataTemplate DataType="{x:Type ParentEntity}" ItemsSource="{Binding ChildsEntities}">
<TextBox Text="{Binding Name}"/>
</HierarchicalDataTemplate>
<!--Template for ChildEntity-->
<DataTemplate DataType="{x:Type ChildEntity}">
<StackPanel Orientation="Horizontal">
<TextBox Text="{Binding Name}"/>
<TextBox Text="{Binding Value}"/>
</StackPanel>
</DataTemplate>
</TreeView.Resources>
</TreeView>
ObservableCollection<ParentEntity> data = new ObservableCollection<ParentEntity>();
treeView.ItemsSource = data ;
Но у меня есть такая структура (из библиотеки):
public class ParentEntity
{
public int UID { get; set; }
public string Name { get; set; }
}
public class ChildEntity
{
public int ParentUID { get; set; }
public string Name { get; set; }
public int Value { get; set; }
}
Как это должно быть обработано? Благодарю.
1 ответ
Я не очень рекомендую это, но я решу проблему, у вас есть XAML
<StackPanel x:Name="root">
<StackPanel.DataContext>
<vm:MainWindowViewModel></vm:MainWindowViewModel>
</StackPanel.DataContext>
<Button Command="{Binding AddRoot}">Add</Button>
<TreeView Height="400">
<TreeView.Resources >
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="True">
</Setter>
</Style>
<vm:HierarchicalDataConverter x:Key="HierarchicalDataConverter"/>
<HierarchicalDataTemplate x:Key="ParentEntityTemplate" DataType="{x:Type vm:ParentEntity}" >
<HierarchicalDataTemplate.ItemsSource>
<MultiBinding Converter="{StaticResource HierarchicalDataConverter}" Mode="TwoWay">
<Binding Mode="OneTime"></Binding>
<Binding Path="DataContext.Items" ElementName="root" ></Binding>
<Binding Path="DataContext.Items.Count" ElementName="root" ></Binding>
</MultiBinding>
</HierarchicalDataTemplate.ItemsSource>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{ Binding Name }"></TextBlock>
<Button Command="{Binding DataContext.AddLeafe, ElementName=root}" CommandParameter="{Binding}">Add item</Button>
</StackPanel>
</HierarchicalDataTemplate>
<DataTemplate x:Key="ChildEntityTemplate" DataType="{x:Type vm:ChildEntity}">
<TextBlock Text="{Binding Name}"></TextBlock>
</DataTemplate>
</TreeView.Resources>
<TreeView.ItemsSource>
<Binding Path="RootItems"/>
</TreeView.ItemsSource>
<TreeView.ItemTemplateSelector>
<vm:ItemTemplateSelector>
</vm:ItemTemplateSelector>
</TreeView.ItemTemplateSelector>
</TreeView>
</StackPanel>
Пространство имен VM
public class MainWindowViewModel : BindableBase
{
public ObservableCollection<object> Items { get; } =
new ObservableCollection<object>(new List<object>(new List<object>
{
new ParentEntity { UID = 1, Name = "Groop1" },
new ChildEntity { ParentUID = 1, Name = "Item1" },
new ParentEntity { UID = 2, Name = "Groop2" },
new ChildEntity { ParentUID = 2, Name = "Item1" },
new ChildEntity { ParentUID = 2, Name = "Item2" },
new ChildEntity { ParentUID = 2, Name = "Item3" }
}));
public CollectionView RootItems { get; }
int count = 2;
public DelegateCommand AddRoot { get; }
public DelegateCommand<ParentEntity> AddLeafe { get; }
public MainWindowViewModel()
{
RootItems = new ListCollectionView(Items) { Filter = (item) => item is ParentEntity };
AddRoot = new DelegateCommand(() =>
{
Items.Add(new ParentEntity { UID = ++count ,Name= "Group"+count});
});
AddLeafe = new DelegateCommand<ParentEntity>((pe) =>
{
Items.Add(new ChildEntity { ParentUID = pe.UID, Name = "Item" + count });
});
}
}
public class ParentEntity
{
public int UID { get; set; }
public string Name { get; set; }
}
public class ChildEntity
{
public int ParentUID { get; set; }
public string Name { get; set; }
public int Value { get; set; }
}
public class ItemTemplateSelector : DataTemplateSelector
{
public override DataTemplate
SelectTemplate(object item, DependencyObject container)
{
FrameworkElement element = container as FrameworkElement;
if (item is ParentEntity)
{
return element.FindResource("ParentEntityTemplate") as DataTemplate;
}
if (item is ChildEntity)
{
return element.FindResource("ChildEntityTemplate") as DataTemplate;
}
return null;
}
}
public class HierarchicalDataConverter : IMultiValueConverter
{
public object Convert(object[] value, Type targetType, object parameter, CultureInfo culture)
{
if (value[0] != null)
{
ParentEntity pe = value[0] as ParentEntity;
var items = value[1] as IEnumerable<object>;
return items.Where((item) => item is ChildEntity && (item as ChildEntity).ParentUID == pe.UID);
}
return null;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Проблема в том, что он воссоздает все дочерние узлы.