使用 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));
}
}
我参考了 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));
}
}