C# 在treeview MVVM中获取父项

C# 在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

我尝试学习使用treeview base one MVVM。我参考本教程

这非常有帮助,我试图通过重写代码来理解它

TreeViewViewModel.cs

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以获取所选项目。但是中产阶级阻止了它。FamilyViewModel
FamilyTreeViewModel
是根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>());
    }