使用 MVVM WPF 在树视图中添加、重命名、删除项目

Add, rename, remove item in treeview with MVVM WPF

我参考了 Josh Smith 的优秀教程来使用 treeview。

https://www.codeproject.com/Articles/26288/Simplifying-the-WPF-TreeView-by-Using-the-ViewMode

我尝试使用此代码修改以添加、删除、重命名此树视图的项目,但我不知道为什么它不更新

重命名项目命令

#region RenameCommand

/// <summary>
/// Returns the command used to execute a search in the family tree.
/// </summary>
public ICommand RenameCommand
{
    get { return _renameCommand; }
}

private class RenameFamilyTreeCommand : ICommand
{
    readonly FamilyTreeViewModel _familyTree;

    public RenameFamilyTreeCommand(FamilyTreeViewModel familyTree)
    {
        _familyTree = familyTree;
    }

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

    event EventHandler ICommand.CanExecuteChanged
    {
        // I intentionally left these empty because
        // this command never raises the event, and
        // not using the WeakEvent pattern here can
        // cause memory leaks.  WeakEvent pattern is
        // not simple to implement, so why bother.
        add { }
        remove { }
    }

    public void Execute(object parameter)
    {
        //MessageBox.Show("Rename command");



        _familyTree._rootPerson.Children[0].Children[0].Header = "Hello";

        if (_familyTree._rootPerson.Children[0] == null)
            return;

        // Ensure that this person is in view.
        if (_familyTree._rootPerson.Children[0].Parent != null)
            _familyTree._rootPerson.Children[0].Parent.IsExpanded = true;

        _familyTree._rootPerson.Children[0].IsSelected = true;
    }
}

#endregion // RenameCommand

添加项目命令

#region AddCommand

    /// <summary>
    /// Returns the command used to execute a search in the family tree.
    /// </summary>
    public ICommand AddCommand
    {
        get { return _addCommand; }
    }

    private class AddFamilyTreeCommand : ICommand
    {
        public FamilyTreeViewModel _familyTree;

        public AddFamilyTreeCommand(FamilyTreeViewModel familyTree)
        {
            _familyTree = familyTree;
        }

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

        event EventHandler ICommand.CanExecuteChanged
        {
            // I intentionally left these empty because
            // this command never raises the event, and
            // not using the WeakEvent pattern here can
            // cause memory leaks.  WeakEvent pattern is
            // not simple to implement, so why bother.
            add { }
            remove { }
        }

        public void Execute(object parameter)
        {
            Person newPerson = new Person();
            newPerson.Header = "New Person";
            newPerson.Name = "1.1.1.75";
            PersonViewModel newPersonViewModel = new PersonViewModel(newPerson);
            ////_rootPerson.Children.Add(newPersonViewModel);


            //_rootPerson.Children.Add(newPersonViewModel);

            //if (newPersonViewModel.Parent != null)
            //    newPersonViewModel.Parent.IsExpanded = true;

            //newPersonViewModel.IsSelected = true;

            _familyTree._rootPerson.Children[0].Children.Add(newPersonViewModel);

            if (_familyTree._rootPerson.Children[0] == null)
                return;

            // Ensure that this person is in view.
            if (_familyTree._rootPerson.Children[0].Parent != null)
                _familyTree._rootPerson.Children[0].Parent.IsExpanded = true;

            _familyTree._rootPerson.Children[0].IsSelected = true;


        }
    }

#endregion // AddCommand

添加命令工作正常,但它似乎是 GUI 未更新。重命名命令不起作用,但 GUI 已更新。我不知道为什么,而且很难访问 person class(使用 parent, person, children,..)

有没有人成功更新 Josh Smith 项目的添加、重命名、删除命令。

p/s:我通过 messagebox.show 进行调试,看到添加和重命名的绑定命令运行良好,但问题是我不知道究竟要使用什么添加、删除、重命名人员在约什·史密斯项目中

添加项目未反映在 UI 中,因为源集合 Person.Children 未实现 INotifyCollectionChanged。 每当你需要动态集合时,添加、删除或移动操作应该更新绑定目标,你应该使用 ObservableCollection<T>,它实现了 INotifyCollectionChanged.

类似适用于 Person.Name 属性。如果您希望 属性 的更改反映到 UI,那么您的视图模型必须实现 INotifyPropertyChanged 并在绑定源(视图型号 属性) 已更改。

一般来说,当一个class作为数据绑定的绑定源时,那么这个class必须实现INotifyPropertyChanged(如果没有实现这个接口,那么数据的表现绑定变得非常糟糕)。
当 属性 的修改应通过调用数据绑定更新 UI (binding.target) 时,修改后的 属性 必须引发 INotifyPropertyChanged.PropertyChanged 事件。
当集合的修改应该通过调用数据绑定来更新 UI(绑定目标)时,修改后的集合必须实现 INotifyCollectionChanged 并引发 INotifyCollectionChanged.CollectionChanged 事件。 ObservableCollection 提供了 INotifyCollectionChanged 的默认实现。

下面的例子遵循了上面的规则。对 Person class 所做的更改应该可以解决您的问题。对数据模型的更改现在将反映在 TreeView:

public class Person : INotifyPropertyChanged
{
    private ObservableCollection<Person> _children = new ObservableCollection<Person>();
    public ObservableCollection<Person> Children
    {
        get { return _children; }
    }

    private string name
    public string Name 
    {
        get => this.name;
        set 
        { 
            this.name = value; 
            OnPropertyChanged();
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
      this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}