更新时间:2023-10-13 20:11:40
添加项目没有反映在 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));
}
}