C# 在treeview MVVM中获取父项
我尝试学习使用treeview base one MVVM。我参考本教程 这非常有帮助,我试图通过重写代码来理解它 TreeViewViewModel.csC# 在treeview MVVM中获取父项,c#,wpf,mvvm,treeviewitem,C#,Wpf,Mvvm,Treeviewitem,我尝试学习使用treeview base one MVVM。我参考本教程 这非常有帮助,我试图通过重写代码来理解它 TreeViewViewModel.cs public class TreeViewViewModel { private ObservableCollection<TreeNode> _firstNode; public static TreeNode _seletectedNode; private ObservableCollection
public class TreeViewViewModel
{
private ObservableCollection<TreeNode> _firstNode;
public static TreeNode _seletectedNode;
private ObservableCollection<TreeNode> _node;
private ICommand _addCommand;
public TreeViewViewModel(TreeNode rootNode) : this(rootNode, null) {}
public TreeViewViewModel(TreeNode rootNode, TreeViewViewModel parentNode)
{
_firstNode = new ObservableCollection<TreeNode>(rootNode.Node);
_node = new ObservableCollection<TreeNode>((from child in rootNode.Node select child).ToList<TreeNode>());
_addCommand = new AddCommand(this);
}
public ObservableCollection<TreeNode> FirstNode
{
get { return _firstNode; }
set { _firstNode = value; }
}
public ObservableCollection<TreeNode> Node
{
get { return _node; }
set { _node = value; }
}
public TreeNode Selected
{
get{ return _seletectedNode; }
set{ _seletectedNode = value;}
}
public ICommand AddCommand
{
get { return _addCommand; }
}
}
MainWindown.xaml.cs
public partial class MainWindow : Window
{
public TreeViewViewModel _TreeView;
public MainWindow()
{
InitializeComponent();
TreeNode rootNode = new TreeNode
{
Name = "David",
Node =
{
new TreeNode
{
Name = "Alberto",
Node =
{
new TreeNode
{
Name = "Zena",
Node =
{
new TreeNode
{
Name = "Nick",
}
}
},
new TreeNode
{
Name = "Sarah",
},
}
},
new TreeNode
{
Name = "Komrade",
}
}
};
_TreeView = new TreeViewViewModel(rootNode);
base.DataContext = _TreeView;
}
}
MainWindow.xaml
<Window x:Class="TreeviewMVVM_Test.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:local="clr-namespace:TreeviewMVVM_Test"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<TextBox Margin="10,35,380,260"/>
<Button Margin="154,27,324,268" Command="{Binding AddCommand}" />
<TreeView x:Name="treeView"
ItemsSource="{Binding FirstNode}"
BorderThickness="0"
Height="Auto" Width="Auto"
Margin="21,84,349,19">
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}" BasedOn="{StaticResource {x:Type TreeViewItem}}">
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
<Setter Property="FontWeight" Value="Normal" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="FontWeight" Value="Bold" />
</Trigger>
</Style.Triggers>
</Style>
</TreeView.ItemContainerStyle>
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Node}">
<TextBlock Text="{Binding Name}" />
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Grid>
</Window>
我的源代码运行良好,我可以从所选节点添加childnode,删除第一级节点,重命名所选节点,获取所选节点。但只有一件事,我不知道如何存储和获取父节点
我读了Josh教程,似乎父节点存储在constructor中。下面是Josh的代码。如果像这样使用,则父节点是TreeView模型,而不是节点。我不想这样,有没有办法使父节点成为TreeNode类型。我想像这样使用_treeView.Seletect.Parent.Name,它应该打印所选节点的父名称
private PersonViewModel(Person person, PersonViewModel parent)
{
_person = person;
_parent = parent;
_children = new ObservableCollection<PersonViewModel>(
(from child in _person.Children
select new PersonViewModel(child, this))
.ToList<PersonViewModel>());
}
private PersonViewModel(Person-Person,PersonViewModel父级)
{
_人=人;
_父母=父母;
_children=新的可观察集合(
(来自儿童本人)
选择新PersonViewModel(子对象,此))
.ToList());
}
父级不应是TreeViewViewModel
,而应是TreeNode
您的TreeNode
相当于Josh的PersonViewModel
在Josh的世界里:
Person
是模型(数据)
PersonViewModel
是以树项形式表示的数据的表示形式
PersonViewModel
构造函数接受两个参数。要显示的数据(Person
),以及对父树项的引用(PersonViewModel
)。然后,构造函数通过迭代数据的子项来创建所有子树项(PersonViewModel
)。(人
)
在您的世界中:
??
是模型(没有)
TreeNode
是一些数据的表示形式,其名称和ID显示为树项。换句话说,TreeNode既是模型又是视图模型(这并不一定是错误的)
但是,您试图在视图中构造数据,这是错误的。你也在从叶子到根向后构建你的树。由于您首先构造子对象,因此无法设置父对象,因为此时不存在父对象
在Josh的世界中,层次结构已经存在于模型中,因此父对象可用。如果您同时构建模型/虚拟机,则需要以不同的方式构建树,以便在创建子级之前父级存在。
我不希望这样
请解释一下您为什么不喜欢它?在MVVM中,如果您觉得需要访问父项,那么您就知道自己做错了。您可以通过添加父属性来访问父VM,不应该有任何理由访问父视图。您可以实现查找父视图然后读取其数据上下文的功能,但这会破坏MVVM。如果Josh的personviewmodel没有父属性,则只需添加一个属性,该属性将返回已提交并存储在_parent中的父属性。构建viewmodels族一次构建一个实例,这样您就可以构建一个父对象,并拥有一个对象,然后可以传递到子对象的ctor中。然后,您可以使用任何给定personviewmodel实例的父属性,无论是在该实例内部还是外部。我这样应用MVVM是错误的。我将再次尝试构建一个正确的MVVM。根据Josh的教程,我有更新代码,但我现在的问题是无法访问PersonViewModel,midde class FamilyTreeViewModel阻止了它。我创建了一个新的帖子,并用新的来源更新到这里,请帮助我看看它。当我生活在Josh的世界中时,问题是我如何从familyTreeViewModel访问项目。例如,我有一个添加按钮来重命名所选项目->我需要获取所选项目->访问PersonViewModel以获取所选项目。但是中产阶级阻止了它。FamilyViewModelFamilyTreeViewModel
是根VM,就像你的TreeViewModel
一样。它可以完全访问所有PersonViewModels
,查看是否选中了它们。请参阅Josh的FindMatches()
函数,该函数迭代所有节点。对于选择,每个节点也引用根VM可能更简单,并且对于他们来说,将自己设置为SelectedNode
,直接在其IsSelected
setter中(假设树是单选)是的,我看到了FindMatches,但他在rootnode中循环所有项以查找项。你能看看我的新帖子吗。我更新代码以适应Josh MVVM。非常感谢你的帮助。
<Window x:Class="TreeviewMVVM_Test.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:local="clr-namespace:TreeviewMVVM_Test"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<TextBox Margin="10,35,380,260"/>
<Button Margin="154,27,324,268" Command="{Binding AddCommand}" />
<TreeView x:Name="treeView"
ItemsSource="{Binding FirstNode}"
BorderThickness="0"
Height="Auto" Width="Auto"
Margin="21,84,349,19">
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}" BasedOn="{StaticResource {x:Type TreeViewItem}}">
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
<Setter Property="FontWeight" Value="Normal" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="FontWeight" Value="Bold" />
</Trigger>
</Style.Triggers>
</Style>
</TreeView.ItemContainerStyle>
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Node}">
<TextBlock Text="{Binding Name}" />
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Grid>
</Window>
private PersonViewModel(Person person, PersonViewModel parent)
{
_person = person;
_parent = parent;
_children = new ObservableCollection<PersonViewModel>(
(from child in _person.Children
select new PersonViewModel(child, this))
.ToList<PersonViewModel>());
}