使用 MVVM WPF 在树视图中添加、重命名、删除项目 [英] Add, rename, remove item in treeview with MVVM WPF

查看:54
本文介绍了使用 MVVM WPF 在树视图中添加、重命名、删除项目的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我参考了 Josh Smith 的优秀教程来使用树视图.

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

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

重命名物品命令

#region RenameCommand///<总结>///返回用于在家族树中执行搜索的命令.///</总结>公共 ICommand 重命名命令{得到 { 返回 _renameCommand;}}私有类 RenameFamilyTreeCommand : ICommand{只读 FamilyTreeViewModel _familyTree;公共重命名FamilyTreeCommand(FamilyTreeViewModel familyTree){_familyTree = 家谱;}public bool CanExecute(对象参数){返回真;}事件 EventHandler ICommand.CanExecuteChanged{//我故意把这些留空是因为//此命令永远不会引发事件,并且//这里不使用 Wea​​kEvent 模式可以//导致内存泄漏.弱事件模式是//实现起来并不简单,何必呢.添加 { }消除 { }}公共无效执行(对象参数){//MessageBox.Show("重命名命令");_familyTree._rootPerson.Children[0].Children[0].Header = "你好";如果(_familyTree._rootPerson.Children[0] == null)返回;//确保此人在视野中.如果(_familyTree._rootPerson.Children[0].Parent != null)_familyTree._rootPerson.Children[0].Parent.IsExpanded = true;_familyTree._rootPerson.Children[0].IsSelected = true;}}#endregion//重命名命令

添加物品命令

#region AddCommand///<总结>///返回用于在家族树中执行搜索的命令.///</总结>公共 ICommand 添加命令{得到 { 返回 _addCommand;}}私有类 AddFamilyTreeCommand : ICommand{公共 FamilyTreeViewModel _familyTree;public AddFamilyTreeCommand(FamilyTreeViewModel familyTree){_familyTree = 家谱;}public bool CanExecute(对象参数){返回真;}事件 EventHandler ICommand.CanExecuteChanged{//我故意把这些留空是因为//此命令永远不会引发事件,并且//这里不使用 Wea​​kEvent 模式可以//导致内存泄漏.弱事件模式是//实现起来并不简单,何必呢.添加 { }消除 { }}公共无效执行(对象参数){人 newPerson = new Person();newPerson.Header = "新人";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);如果(_familyTree._rootPerson.Children[0] == null)返回;//确保此人在视野中.如果(_familyTree._rootPerson.Children[0].Parent != null)_familyTree._rootPerson.Children[0].Parent.IsExpanded = true;_familyTree._rootPerson.Children[0].IsSelected = true;}}#endregion//添加命令

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

是否有人成功地更新了 Josh Smith 项目的添加、重命名、删除命令.

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

解决方案

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

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

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

以下示例遵循上述规则.对 Person 类所做的更改应该可以解决您的问题.对数据模型的更改现在将反映在 TreeView 中:

public class Person : INotifyPropertyChanged{私有 ObservableCollection_children = new ObservableCollection();公共 ObservableCollection孩子们{得到 { 返回 _children;}}私有字符串名称公共字符串名称{得到 =>这个.name;放{this.name = 值;OnPropertyChanged();}}公共事件 PropertyChangedEventHandler PropertyChanged;protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null){this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));}}

I refer excellent tutorial of Josh Smith to work with treeview.

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

I try to modified with this code to add, remove, rename item to this treeview but I don't know why it not update

Rename item command

#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

Add item command

#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

Add command working fine but it's seem to be GUI not update. Rename command is not working but GUI is updated. I don't know reason why, And it's hard to access person class (use parent, person, children,..)

Is there anyone successfully update add, rename, remove command to Josh Smith project.

p/s: I debug by messagebox.show and see binding command for add and rename are working well, But the problem is I don't know what exactly to use Add, remove, rename person in Josh Smith project

解决方案

Adding items is not reflected in the UI, because the source collection Person.Children doesn't implement INotifyCollectionChanged. Whenever you need dynamic collections, where add, remove or move operations should update the binding target, you should use the ObservableCollection<T>, which implements INotifyCollectionChanged.

Similar applies to the Person.Name property. If you want a property's change to be reflected to the UI, then your view model must implement INotifyPropertyChanged and raise the INotifyPropertyChanged.PropertyChanged event whenever the binding source (the view model property) has changed.

Generally, when a class serves as a binding source for data binding, then this class must implement INotifyPropertyChanged (if this interface is not implemented, then the performance of data binding becomes very bad).
When the modification of a property should update the UI (binding.target) by invoking the data binding, then the modified property must raise the INotifyPropertyChanged.PropertyChanged event.
When the modification of a collection should update the UI (binding target) by invoking the data binding, then the modified collection must implement INotifyCollectionChanged and raise the INotifyCollectionChanged.CollectionChanged event. ObservableCollection provides a default implementation of INotifyCollectionChanged.

The following example follows the above rules. The changes made to the Person class should fix your issues. Changes to the data model will now be reflected in the 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));
    }
}

这篇关于使用 MVVM WPF 在树视图中添加、重命名、删除项目的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆