在充分尊重WPF MVVM的情况下,在每个节点中创建具有不同子对象的TreeView
本文关键字:创建 TreeView 对象 节点 WPF 情况下 MVVM | 更新日期: 2023-09-27 18:11:23
我想在完全尊重Wpf MVVM:的情况下创建如下树视图
根//0级
B1-儿童1//1级
B1-1-儿童1-1//2级
B1-2-儿童1-2
B1-3-。。。
B2-Child2/Level1
B2-1儿童2-1//2级
B2-2儿童2-2
B2-3。。。
正如你所看到的,我有三级树视图。
0级:根(始终修复(
级别1:两个孩子(总是修复(
级别2:动态子级,它们是从两个不同的类创建的
所以我的问题是如何在级别2中为级别1中的每个节点创建不同的子级。
我使用了下面的代码,但在一级中,我的孩子总是和父母一样。
我已经看了这个网站上以及网上提出的许多解决方案。。。但就是不知道怎么做…
我的尝试:
public class MyViewModel
{
//private ReadOnlyCollection<AttributesMapDocViewModel> _attributeMapDoc;
public object _document;
#region Methodes
private List<Level0ViewModel> _myDoc;
public List<Level0ViewModel> MyDoc
{
get { return _myDoc; }
set
{
_myDoc = value;
}
}
#endregion
#region Constructeur
public MyViewModel()
{
MyDoc = new List<Level0ViewModel>()
{
new Level0ViewModel("Root",_document), //_document conatins data from xml file (code not shown)
};
}
#endregion
}
public class Level0ViewModel : ViewModelBase
{
private List<Level1ViewModel> _childLevel1;
public Level0ViewModel(string name, object myObj)
{
ChildLeve0Name = name;
ChildLevel1 = new List<Level1ViewModel>()
{
new Level1ViewModel("Child1",myObj),
new Level1ViewModel("Child2",myObj)
};
}
public List<Level1ViewModel> ChildLevel1
{
get
{
return _childLevel1;
}
set
{
SetProperty(ref _childLevel1, value, () => ChildLevel1);
}
}
public string ChildLeve0Name { get; set; }
}
public class Level1ViewModel : ViewModelBase
{
private ObservableCollection<Level2SecondTypeViewModel> _childLevel2SecondType;
public ObservableCollection<Level2SecondTypeViewModel> ChildLevel2SecondType
{
get { return _childLevel2SecondType; }
set
{
if (_childLevel2SecondType != value)
{
SetProperty(ref _childLevel2SecondType, value, () => ChildLevel2SecondType);
}
}
}
private ObservableCollection<Level2FirstTypeViewModel> _childLevel2FirstType;
public ObservableCollection<Level2FirstTypeViewModel> ChildLevel2FirstType
{
get { return _childLevel2FirstType; }
set
{
if (_childLevel2FirstType != value)
{
SetProperty(ref _childLevel2FirstType, value, () => ChildLevel2FirstType);
}
}
}
public Level1ViewModel(string name, object mapAtt)
{
ChildLevel1Name = name;
ChildLevel2FirstType = new ObservableCollection<Level2FirstTypeViewModel>();
foreach (FirstType myFirstType in mapAtt.FirstTypes)
{
ChildLevel2FirstType.Add(new Level2FirstTypeViewModel(myFirstType));
}
ChildLevel2SecondType = new ObservableCollection<Level2SecondTypeViewModel>();
foreach (SecondType mySecondType in mapAtt.SecondTypes)
{
ChildLevel2SecondType.Add(new Level2SecondTypeViewModel(mySecondType));
}
}
public string ChildLevel1Name
{
get;
set;
}
}
public class Level2FirstTypeViewModel : ViewModelBase
{
public Level2FirstTypeViewModel(FirstType fType)
{
FirstTypeName = fType.name;
}
public string FirstTypeName
{
get;
set;
}
}
public class Level2SecondTypeViewModel
{
public Level2SecondTypeViewModel(SecondType sType)
{
SecondTypeName = sType.name;
}
public string SecondTypeName
{
get;
set;
}
}
<TreeView ItemsSource="{Binding MyDoc}" >
<TreeView.Resources>
<HierarchicalDataTemplate ItemsSource="{Binding MapAttDef}" DataType="{x:Type local:Level0ViewModel}">
<Label Content="{Binding ChildLeve0Name}"/>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding ChildLevel2SecondType}" DataType="{x:Type local:Level1ViewModel}">
<Label Content="{Binding ChildLevel1Name}"/>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:Level2SecondTypeViewModel}">
<Label Content="{Binding FirstTypeName}"/>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:Level2FirstTypeViewModel}">
<Label Content="{Binding SecondTypeName}"/>
</HierarchicalDataTemplate>
</TreeView.Resources>
我的尝试给了我这样的东西(这根本不是我想要的!!(:
根//0级
B1-儿童1//1级
B1-1-儿童1-1//2级
B1-2-儿童1-2
B1-3-。。。
B2-Child2/Level1
B2-1儿童1-1/2级
B2-2儿童1-2
B2-3。。。
放弃这些属性:Level1ViewModel.ChildLevel2FirstType
和Level1ViewModel.ChildLevel2SecondType
。
你需要为孩子们单独收集。此集合的项类型取决于继承层次结构,并且应该是最近的公共祖先(最坏的情况是object
(,也就是说,如下所示:
public Level1ViewModel
{
public ObservableCollection<object> ChildLevel2
{
// ...
}
// ...
}
带有这些更改的标记将如下所示:
<!-- Level 1 -->
<HierarchicalDataTemplate DataType="{x:Type local:Level1ViewModel}" ItemsSource="{Binding ChildLevel2}">
<Label Content="{Binding ChildLevel1Name}"/>
</HierarchicalDataTemplate>
<!-- Level 1 -->
<DataTemplate DataType="{x:Type local:Level2FirstTypeViewModel}">
<Label Content="{Binding SecondTypeName}"/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:Level2SecondTypeViewModel}">
<Label Content="{Binding FirstTypeName}"/>
</DataTemplate>
请注意,HierarchicalDataTemplate
只能用于分层数据源。对于非分层的(如Level2FirstTypeViewModel
和CCD_ 6(使用常规CCD_。
public class BaseTreeViewItem<TSource, TParent> : ViewModelBase
{
// add static field to hold selected Item
public static BaseTreeViewItem<TSource, TParent> SelectedChild { get; set; }
private bool _isSelected;
public bool IsSelected
{
get { return _isSelected; }
set
{
if (_isSelected == value) return;
if (SelectedChild != null)
{
SelectedChild.IsSelected = false;
SelectedChild = null;
}
_isSelected = value;
if (_isSelected)
SelectedChild = this;
// NotifyPropertyChanged
}
}
public TParent Parent
{
get;
private set;
}
public BaseTreeViewItem(string name, TSource myObj, TParent parent)
{
ChildName = name;
DataSource = myObj;
Parent = parent;
}
public string ChildName { get; set; }
public TSource DataSource { get; set; }
public override string ToString()
{
return ChildName;
}
}
// Node
public class MyTreeViewItem<TChild, TSource, TParent> : BaseTreeViewItem<TSource, TParent>, IDeleteItem
where TParent : IDeleteItem
where TChild : class
{
public ObservableCollection<TChild> Children { get; set; }
public MyTreeViewItem(string name, TSource myObj, TParent parent)
:base(name,myObj, parent)
{
Children = new ObservableCollection<TChild>();
}
protected virtual void InitChild()
{
}
public void DeleteItem(object myTreeViewItem)
{
Children.Remove(myTreeViewItem as TChild);
}
public static void DeleteSelectedItem()
{
if (SelectedChild != null && SelectedChild.Parent != null)
{
SelectedChild.Parent.DeleteItem(SelectedChild);
}
}
}
public class Level0ViewModel : MyTreeViewItem<Level1ViewModel, XmlDocument, IDeleteItem>
{
protected override sealed void InitChild()
{
base.InitChild();
Children.Add(new Level1ViewModel("Child1", new Level1Src(), this));
Children.Add(new Level1ViewModel("Child2", new Level1Src(), this));
}
public Level0ViewModel(string name, XmlDocument myObj) :
base(name, myObj,null)
{
InitChild();
}
}
public class Level1ViewModel : MyTreeViewItem<Level2TypeViewModel, Level1Src, Level0ViewModel>
{
public Level1ViewModel(string name, Level1Src myObj, Level0ViewModel parent)
: base(name, myObj, parent)
{
InitChild();
}
protected override sealed void InitChild()
{
base.InitChild();
foreach (FirstType myFirstType in DataSource.FirstTypes)
{
Children.Add(new Level2TypeViewModel(myFirstType, this));
}
foreach (SecondType mySecondType in DataSource.SecondTypes)
{
Children.Add(new Level2TypeViewModel(mySecondType, this));
}
}
// Use linq if tou want child by type
public IEnumerable<Level2TypeViewModel> ChildType1
{
get
{
return Children.Where(item => item.DataSource is FirstType);
}
}
public IEnumerable<Level2TypeViewModel> ChildType2
{
get
{
return Children.Where(item => item.DataSource is SecondType);
}
}
}
public class LevelType
{
public string Name;
}
public class FirstType : LevelType
{
}
public class SecondType : LevelType
{
}
public class Level2TypeViewModel : BaseTreeViewItem<LevelType, Level1ViewModel>
{
public Level2TypeViewModel(LevelType sType, Level1ViewModel parent)
: base(sType.Name, sType, parent)
{
}
}
我的数据源是
public Level0ViewModel TreeModel
{
get
{
return new Level0ViewModel("Root", new XmlDocument());
}
}
对于TreeView数据模板,请使用
<TreeView DataContext="{Binding ElementName=UI, Path=TreeModel}">
<TreeView.Items>
<TreeViewItem Header="{Binding ChildName}" ItemsSource="{Binding Path=Children}" >
<TreeViewItem.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children}">
<Label Content="{Binding ChildName}"></Label>
</HierarchicalDataTemplate>
</TreeViewItem.ItemTemplate>
</TreeViewItem>
</TreeView.Items>
</TreeView>
第一个treeviewItem用于显示根节点。如果你不想使用它您可以将数据源更改为
public MyTreeViewItem<Level0ViewModel,object> TreeModel
{
get
{
MyTreeViewItem<Level0ViewModel,object> src = new MyTreeViewItem<Level0ViewModel, object>("Root", null);
src.Children.Add(new Level0ViewModel("toto", new XmlDocument()));
return src;
}
}
和数据模板到
<TreeView DataContext="{Binding ElementName=UI, Path=TreeModel}" ItemsSource="{Binding Children}">
<TreeViewItem.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children}">
<Label Content="{Binding ChildName}"></Label>
</HierarchicalDataTemplate>
</TreeViewItem.ItemTemplate>
</TreeView>
样本方式
public class TreeViewItemViewModel : ViewModelBase
{
// add static field to hold selected Item
public static TreeViewItemViewModel SelectedChild { get; set; }
public TreeViewItemViewModel Parent{ get; private set;}
public string ChildName { get; set; }
public object DataSource { get; set; }
private readonly ObservableCollection<TreeViewItemViewModel> _children;
public ObservableCollection<TreeViewItemViewModel> Children
{
get
{
return _children;
}
}
private bool _isSelected;
public bool IsSelected
{
get { return _isSelected; }
set
{
if (_isSelected == value) return;
if (SelectedChild != null)
{
SelectedChild.IsSelected = false;
SelectedChild = null;
}
_isSelected = value;
if (_isSelected)
SelectedChild = this;
// NotifyPropertyChanged
}
}
public TreeViewItemViewModel(string name, object myObj, TreeViewItemViewModel parent)
{
ChildName = name;
DataSource = myObj;
Parent = parent;
_children = new ObservableCollection<TreeViewItemViewModel>();
}
public override string ToString()
{
return ChildName;
}
protected virtual void InitChild()
{
}
public void DeleteItem(TreeViewItemViewModel myTreeViewItem)
{
Children.Remove(myTreeViewItem);
}
public static void DeleteSelectedItem()
{
if (SelectedChild != null && SelectedChild.Parent != null)
{
SelectedChild.Parent.DeleteItem(SelectedChild);
}
}
}
如果你的视图模型中有一个选定的项目,你可以使用这种方法
公共类TreeViewItemViewModel:ViewModelBase{
// add static field to hold selected Item
public static TreeViewItemViewModel SelectedChild { get; set; }
public TreeViewItemViewModel Parent{ get; private set;}
public string ChildName { get; set; }
public object DataSource { get; set; }
private readonly ObservableCollection<TreeViewItemViewModel> _children;
public ObservableCollection<TreeViewItemViewModel> Children
{
get
{
return _children;
}
}
private bool _isSelected;
public bool IsSelected
{
get { return _isSelected; }
set
{
if (_isSelected == value) return;
if (SelectedChild != null)
{
SelectedChild.IsSelected = false;
SelectedChild = null;
}
_isSelected = value;
if (_isSelected)
SelectedChild = this;
// NotifyPropertyChanged
}
}
public TreeViewItemViewModel(string name, object myObj, TreeViewItemViewModel parent)
{
ChildName = name;
DataSource = myObj;
Parent = parent;
_children = new ObservableCollection<TreeViewItemViewModel>();
}
public override string ToString()
{
return ChildName;
}
protected virtual void InitChild()
{
}
public void DeleteItem(TreeViewItemViewModel myTreeViewItem)
{
Children.Remove(myTreeViewItem);
}
public static void DeleteSelectedItem()
{
if (SelectedChild != null && SelectedChild.Parent != null)
{
SelectedChild.Parent.DeleteItem(SelectedChild);
}
}
}