Wpf 在treview MVVM中获取所选项目
我试图通过参考Josh的教程将MVVM应用于treeview 这是我的全部源代码 TreeNode.csWpf 在treview MVVM中获取所选项目,wpf,mvvm,treeviewitem,Wpf,Mvvm,Treeviewitem,我试图通过参考Josh的教程将MVVM应用于treeview 这是我的全部源代码 TreeNode.cs public class TreeNode { private ObservableCollection<TreeNode> _children = new ObservableCollection<TreeNode>(); public ObservableCollection<TreeNode> Children {
public class TreeNode
{
private ObservableCollection<TreeNode> _children = new ObservableCollection<TreeNode>();
public ObservableCollection<TreeNode> Children
{
get { return _children; }
set { _children = value; }
}
public string Name { get; set; }
public string ID { get; set; }
}
我的目标是,当我单击添加命令时,它将显示选定项名称和父选定项名称。但问题是TreeView模型中没有任何东西可以访问TreeNodeView模型
中产阶级的TreeViewModel阻止他们在乔希的世界里访问TreeNodeViewModel的财产,根据我对你前面问题的评论。将SelectedNode添加到TreeViewViewModel,并在节点选定设置器中进行设置:
private TreeNodeViewModel(TreeNode node, TreeNodeViewModel parent, TreeViewViewModel root)
{
_node = node;
_parent = parent;
_root = root;
//snip rest
}
public bool IsSelected
{
get { return _isSelected; }
set
{
if (value != _isSelected)
{
_isSelected = value;
this.OnPropertyChanged("IsSelected");
if (_isSelected) { _root.SelectedNode = this; }
}
}
}
如果您关心应用程序的性能,则始终在绑定源上实现
INotifyPropertyChanged
——即使您没有引发PropertyChanged
事件(因为属性不会更改)
在您的例子中,TreeNode
充当TreeView
的绑定源。因此,TreeNode
应该实现INotifyPropertyChanged
由于IsSelected
和IsExpanded
肯定是节点的属性,因此它们应该是TreeNode
的成员。这使得TreeNodeViewModel
冗余。删除TreeNodeViewModel
还将删除重复的属性,例如子属性
或名称
及其笨拙的初始化。因此,在我的示例中,我仅使用
TreeNode
和treeviwmodel
合并了这两个类
还要检查ICommand.CanExecuteChanged
事件的正确实现。我已经在我的例子中修正了它
使用nameof
,而不是将成员或类型的字符串值传递给方法。我还修复了在调用OnPropertyChanged
时出现的问题。有关OnPropertyChanged
事件invocator的最佳实现,请参阅
树的操作(例如,向树中添加/从树中删除项目)应始终集中在管理树的类中进行,例如,TreeViewModel
。我在这个类中实现了相应的方法。命令现在调用此方法来操作树
问题的解决方案是将SelectedNode
属性添加到管理树的类中,在您的示例中,该类就是treeviwmodel
。treeviwmodel
侦听TreeNode
的SelctedChanged
事件以更新treeviwmodel.SelectedNode
属性
TreeNode.cs
public class TreeNode : INotifyPropertyChanged
{
public event EventHandler SelectedChanged;
public event PropertyChangedEventHandler PropertyChanged;
private ObservableCollection<TreeNode> _children;
private TreeNode _parent;
private TreeNode _selectedTreeNode;
private string _name;
private string _id;
private bool _isExpanded;
private bool _isSelected;
public TreeNode() => this(null);
public TreeNode(TreeNode parent)
{
_parent = parent;
_children = new ObservableCollection<TreeNodeViewModel>();
}
public ObservableCollection<TreeNode> Children
{
get => _children;
set
{
if (value != _children)
{
_children = value;
OnPropertyChanged(nameof(this.Children));
}
}
}
public TreeNode Parent
{
get => _parent;
set
{
if (value != _parent)
{
_parent = value;
OnPropertyChanged(nameof(this.Parent));
}
}
}
public string Name
{
get => _name;
set
{
if (value != _name)
{
_name = value;
OnPropertyChanged(nameof(this.Name));
}
}
}
public string Id
{
get => _id;
set
{
if (value != _id)
{
_id = value;
OnPropertyChanged(nameof(this.Id));
}
}
}
public bool IsExpanded
{
get => _isExpanded;
set
{
if (value != _isExpanded)
{
_isExpanded = value;
OnPropertyChanged(nameof(this.IsExpanded));
}
// Expand all the way up to the root.
if (_isExpanded && _parent != null)
_parent.IsExpanded = true;
}
}
public bool IsSelected
{
get => _isSelected;
set
{
if (value != _isSelected)
{
_isSelected = value;
OnPropertyChanged(nameof(this.IsSelected));
OnSelectionChanged();
}
}
}
private void OnSelectionChanged()
{
this.SelectedChanged?.Invoke(this, EventArgs.Empty);
}
private void OnPropertyChanged(string propertyName)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class TreeViewModel : INotifyPropertyChanged
{
private readonly ObservableCollection<TreeNode> _firstLevel;
private readonly TreeNode _rootNode;
private TreeNode _selectedTreeNode;
private ICommand _addCommand;
private ICommand _removeCommand;
public TreeViewModel(TreeNode rootNode)
{
_rootNode = rootNode;
_firstLevel = new ObservableCollection<TreeNode>(_rootNode.Children);
_addCommand = new AddCommand(this);
_removeCommand = new RemoveCommand(this);
}
public void AddNode(TreeNode treeNode)
{
treeNode.SelectedChanged += OnTreeNodeSelectedChanged;
this.FirstLevel.Add(treeNode);
}
public void RemoveNode(TreeNode treeNode)
{
treeNode.SelectedChanged -= OnTreeNodeSelectedChanged;
this.FirstLevel.Remove(treeNode);
}
public void OnTreeNodeSelectedChanged(object sender, EventArgs e)
{
var treeNode = sender as TreeNode;
if (treeNode.isSelected)
{
this.SelectedNode = treeNode;
}
}
private void OnPropertyChanged(string propertyName)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public TreeNode RootNode => _rootNode;
public TreeNode SelectedNode
{
get => _selectedNode;
set
{
if (value != _selectedNode)
{
_selectedNode = value;
OnPropertyChanged(nameof(this.SelectedNode));
}
}
}
public ObservableCollection<TreeNode> FirstLevel => _firstLevel;
public ICommand AddCommand => _addCommand;
public ICommand RemoveCommand => _removeCommand;
}
public class AddCommand : ICommand
{
private TreeViewModel _tree;
public AddCommand(TreeViewModel tree)
{
_tree = tree;
}
public event EventHandler CanExecuteChanged
{
add => CommandManager.RequerySuggested += value;
remove => CommandManager.RequerySuggested -= value;
}
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
_tree.AddNode(new TreeNode(_tree.RootNode));
//Show Selected item's name
MessageBox.Show(_tree.SelectedNode.Name);
}
}
public class AddCommand : ICommand
{
private TreeViewModel _tree;
public AddCommand(TreeViewModel tree)
{
_tree = tree;
}
public event EventHandler CanExecuteChanged
{
add => CommandManager.RequerySuggested += value;
remove => CommandManager.RequerySuggested -= value;
}
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
_tree.RemoveNode(parameter as TreeNode);
}
}
RemoveCommand.cs
public class TreeNode : INotifyPropertyChanged
{
public event EventHandler SelectedChanged;
public event PropertyChangedEventHandler PropertyChanged;
private ObservableCollection<TreeNode> _children;
private TreeNode _parent;
private TreeNode _selectedTreeNode;
private string _name;
private string _id;
private bool _isExpanded;
private bool _isSelected;
public TreeNode() => this(null);
public TreeNode(TreeNode parent)
{
_parent = parent;
_children = new ObservableCollection<TreeNodeViewModel>();
}
public ObservableCollection<TreeNode> Children
{
get => _children;
set
{
if (value != _children)
{
_children = value;
OnPropertyChanged(nameof(this.Children));
}
}
}
public TreeNode Parent
{
get => _parent;
set
{
if (value != _parent)
{
_parent = value;
OnPropertyChanged(nameof(this.Parent));
}
}
}
public string Name
{
get => _name;
set
{
if (value != _name)
{
_name = value;
OnPropertyChanged(nameof(this.Name));
}
}
}
public string Id
{
get => _id;
set
{
if (value != _id)
{
_id = value;
OnPropertyChanged(nameof(this.Id));
}
}
}
public bool IsExpanded
{
get => _isExpanded;
set
{
if (value != _isExpanded)
{
_isExpanded = value;
OnPropertyChanged(nameof(this.IsExpanded));
}
// Expand all the way up to the root.
if (_isExpanded && _parent != null)
_parent.IsExpanded = true;
}
}
public bool IsSelected
{
get => _isSelected;
set
{
if (value != _isSelected)
{
_isSelected = value;
OnPropertyChanged(nameof(this.IsSelected));
OnSelectionChanged();
}
}
}
private void OnSelectionChanged()
{
this.SelectedChanged?.Invoke(this, EventArgs.Empty);
}
private void OnPropertyChanged(string propertyName)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class TreeViewModel : INotifyPropertyChanged
{
private readonly ObservableCollection<TreeNode> _firstLevel;
private readonly TreeNode _rootNode;
private TreeNode _selectedTreeNode;
private ICommand _addCommand;
private ICommand _removeCommand;
public TreeViewModel(TreeNode rootNode)
{
_rootNode = rootNode;
_firstLevel = new ObservableCollection<TreeNode>(_rootNode.Children);
_addCommand = new AddCommand(this);
_removeCommand = new RemoveCommand(this);
}
public void AddNode(TreeNode treeNode)
{
treeNode.SelectedChanged += OnTreeNodeSelectedChanged;
this.FirstLevel.Add(treeNode);
}
public void RemoveNode(TreeNode treeNode)
{
treeNode.SelectedChanged -= OnTreeNodeSelectedChanged;
this.FirstLevel.Remove(treeNode);
}
public void OnTreeNodeSelectedChanged(object sender, EventArgs e)
{
var treeNode = sender as TreeNode;
if (treeNode.isSelected)
{
this.SelectedNode = treeNode;
}
}
private void OnPropertyChanged(string propertyName)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public TreeNode RootNode => _rootNode;
public TreeNode SelectedNode
{
get => _selectedNode;
set
{
if (value != _selectedNode)
{
_selectedNode = value;
OnPropertyChanged(nameof(this.SelectedNode));
}
}
}
public ObservableCollection<TreeNode> FirstLevel => _firstLevel;
public ICommand AddCommand => _addCommand;
public ICommand RemoveCommand => _removeCommand;
}
public class AddCommand : ICommand
{
private TreeViewModel _tree;
public AddCommand(TreeViewModel tree)
{
_tree = tree;
}
public event EventHandler CanExecuteChanged
{
add => CommandManager.RequerySuggested += value;
remove => CommandManager.RequerySuggested -= value;
}
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
_tree.AddNode(new TreeNode(_tree.RootNode));
//Show Selected item's name
MessageBox.Show(_tree.SelectedNode.Name);
}
}
public class AddCommand : ICommand
{
private TreeViewModel _tree;
public AddCommand(TreeViewModel tree)
{
_tree = tree;
}
public event EventHandler CanExecuteChanged
{
add => CommandManager.RequerySuggested += value;
remove => CommandManager.RequerySuggested -= value;
}
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
_tree.RemoveNode(parameter as TreeNode);
}
}
用于绑定到树视图中选定项的MVVM纯方法是使用类
公共类perTreeViewHelper:行为
{
公共对象边界SelectedItem
{
get=>GetValue(BoundSelectedItemProperty);
set=>SetValue(BoundSelectedItemProperty,value);
}
公共静态只读从属属性BoundSelectedItemProperty=
DependencyProperty.Register(“BoundSelectedItem”,
类型(对象),
类型(perTreeViewHelper),
新的FrameworkPropertyMetadata(空,
默认情况下,FrameworkPropertyMetadataOptions.BindsTwoWay,
OnBoundSelectedItemChanged);
BoundSelectedItemChanged上的私有静态无效(DependencyObject对象、DependencyPropertyChangedEventArgs参数)
{
如果(args.NewValue为perTreeViewItemViewModelBase项)
{
item.IsSelected=true;
}
}
受保护的覆盖无效附加()
{
base.onatached();
AssociatedObject.SelectedItemChanged+=OnTreeViewSelectedItemChanged;
}
附加时受保护的覆盖无效()
{
AssociatedObject.SelectedItemChanged-=OnTreeViewSelectedItemChanged;
base.OnDetaching();
}
私有无效OnTreeViewSelectedItemChanged(对象对象对象、RoutedPropertyChangedEventArgs参数)
{
BoundSelectedItem=args.NewValue;
}
}
有关其在my.“show”-在绑定到TreeViewModel的视图中使用的更多详细信息?顺便说一句,您的TreeViewModel(坏名字,应该是TreeViewModel)没有SelectedItem属性我在TreeViewModel中创建了一个类似SelectedItem的属性,但如何处理它?因为选定项在TreeNode虚拟机中,所以我无法访问它。您说您有一个
SelectedItem
属性在树虚拟机中,但您无法访问它,因为它在TreeNode虚拟机中?命令在树VM中,树VM被传递给command类(该类不应该存在,但这是另一个问题),因此您可以从命令执行方法访问它。@asaf92我仍然不理解您的理想。如何从treeVM访问所选项目。我可以添加属性SelectedNode,但它如何将其引用到TReeNode vm中的选定节点我如何将根传递给第三个参数构造函数?从TreeViewModel中,我们只是通过公共TreeNode节点(TreeNode节点)运行,根节点没有参数,如果我更改此参数的签名,我得到了很多IssueTreeViewModel根,这里的根应该是TreeNode,如果是TreeNode节点,没有选择的节点。如果它是一个TreeViewModel,则没有根(我们只有公共TreeNoDeviceModel _rootNode;),您需要更改构造函数的签名,并将TreeViewModel作为依赖项传递,这样才能工作。你说的“很多问题”是什么意思?忽略命名。它应该是“树”而不是“根”,我的意思是它是从treeview模型放到构造函数中的根,这个构造函数中只有一个元素是treenode模型的根,但它是treenode,而不是treeview