我尝试学习使用基于树 View 的MVVM。我引用本教程
https://www.codeproject.com/Articles/26288/Simplifying-the-WPF-TreeView-by-Using-the-ViewMode

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

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; }
    }
}

TreeNode.cs
public class TreeNode : INotifyPropertyChanged
{
    private ObservableCollection<TreeNode> _Node = new ObservableCollection<TreeNode>();

    private string _Name;
    private string _ID;

    private bool _isExpanded;
    private bool _isSelected;

    public ObservableCollection<TreeNode> Node
    {
        get { return _Node; }
        set
        {
            _Node = value;
            OnPropertyChanged("Node");
        }
    }

    public string Name
    {
        get { return _Name; }
        set { _Name = value; OnPropertyChanged("Name"); }
    }

    public string ID
    {
        get { return _ID; }
        set { _ID = value; OnPropertyChanged("ID");}
    }

    public bool IsExpanded
    {
        get { return _isExpanded; }
        set
        {
            if (value != _isExpanded)
            {
                _isExpanded = value;
                this.OnPropertyChanged("IsExpanded");
            }
        }
    }

    public bool IsSelected
    {
        get { return _isSelected; }
        set
        {
            if (value != _isSelected)
            {
                _isSelected = value;
                this.OnPropertyChanged("IsSelected");

                if (_isSelected) {TreeViewViewModel._seletectedNode = this;}
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

}

AddCommand.cs
public class AddCommand : ICommand
{
    private TreeViewViewModel _TreeView;

    public AddCommand(TreeViewViewModel treeView)
    {
        _TreeView = treeView;
    }

    public event EventHandler CanExecuteChanged;

    public bool CanExecute(object parameter)
    {
        return true;
    }

    public void Execute(object parameter)
    {
        //Show Selected item
        //MessageBox.Show(_TreeView.Selected.Name);

        //Add first level item
        //_TreeView.FirstNode.Add(new TreeNode { Name = "Hihi" });

        //Rename selected item
        //_TreeView.Selected.Name = "Hello";

        //Remove first level item
        //_TreeView.FirstNode.Remove(_TreeView.Selected);

        //Add selected item
        //_TreeView.Selected.Node.Add(new TreeNode { Name = "Hihi" });

    }
}

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>

我的源代码工作正常,我可以从所选节点添加子节点,删除第一级节点,重命名所选节点,获取所选节点。但是只有一件事,我不知道如何存储和获取父节点

我仔细阅读过Josh教程,似乎是父节点存储在构造器中。以下是Josh的代码。如果我使用类似的父节点是TreeViewViewModel,而不是节点。我不想那样,有没有办法使父节点成为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>());
    }

最佳答案

父级不应该是TreeViewViewModel,而应该是TreeNode

您的TreeNode相当于Josh的PersonViewModel

在Josh的世界中:
Person是模型(数据)
PersonViewModel是表示作为树项显示的数据的表示形式。
PersonViewModel构造函数带有两个参数。要显示的数据(Person),以及对父树项目的引用(PersonViewModel)。然后,构造函数通过迭代数据的子项来创建所有子树项(PersonViewModel)。 (Person)

在您的世界中:
??是模型(没有任何模型)
TreeNode是一些数据的表示,其名称和ID作为树项显示。换句话说,TreeNode既是模型又是 View 模型(不一定是错误的)

但是,您试图在 View 中构造数据,这是错误的。您还将从叶子到根向后构造和向后的树。由于首先要构造子代,因此无法设置父代,因为此时父代不存在。

在Josh的世界中,模型中已经存在层次结构,因此可以使用父级。如果同时构建模型/VM,则需要以其他方式构建树,以便在创建子代之前存在父代。

关于c# - 在Treeview MVVM中获取父项,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/62340104/

10-12 06:54