Wpf 从另一个控件的HierarchycalDataTemplate设置一个控件的属性
我有这样一个viewmodel:Wpf 从另一个控件的HierarchycalDataTemplate设置一个控件的属性,wpf,datagrid,treeview,binding,Wpf,Datagrid,Treeview,Binding,我有这样一个viewmodel: public abstract class ViewModelBase : INotifyPropertyChanged { public abstract string Header { get; } public abstract IEnumerable<ViewModelBase> Nodes { get; } public abstract IEnumerable GridData { get; } //
public abstract class ViewModelBase : INotifyPropertyChanged {
public abstract string Header { get; }
public abstract IEnumerable<ViewModelBase> Nodes { get; }
public abstract IEnumerable GridData { get; }
// following are hooked up to PropertyChanged event in the standard way
public bool IsSelected { get; set; }
public bool IsExpanded { get; set; }
}
但是,这会给出一个错误“找不到触发器目标“dataGrid”。我如何让它工作,我做错了什么?以下是我通常针对这种情况的解决方案:
RootVM
。此VM包含根节点和SelectedNode
属性李>
RootVM.SelectedNode.GridData
SelectedNode
属性。这里的问题是不能直接绑定它(treeview中的SelectedItem
属性是只读的),但这是可以解决的。我更喜欢使用附加行为,有些人更喜欢继承treeView-这取决于你这似乎是一个很好的方法来让它工作。找不到
dataGrid
名称的原因是您试图访问位于不同位置的元素,这意味着数据模板内的元素无法“看到”该模板外的元素
要解决这个问题,您可以执行以下操作。您需要为用户控件
(或窗口
,任何包含您的树状视图
和数据网格
)创建另一个视图模型。我们将其称为MyTreeViewModel:
public class MyTreeViewModel : INotifyPropertyChanged // Better to implement this interface in some base class for all your view models
{
private TreeItemViewModelBase _selectedNode;
public IEnumerable<TreeItemViewModelBase> TopLevelNodes
{
get { yield return new TopLevelTreeNodeViewModel(); // Subclass of your base class for tree nodes (ViewModelBase) }
}
public TreeItemViewModelBase SelectedNode
{
get { return _selectedNode; }
set
{
_selectedNode = value;
RaisePropertyChanged("SelectedNode");
}
}
}
然后,需要修改ViewModelBase(我建议将其重命名为TreeItemViewModelBase
,以避免混淆):
公共抽象类TreeItemViewModelBase:INotifyPropertyChanged
{
私立学校当选;
public TreeItemViewModelBase(MyTreeViewModel parentViewModel)
{
ParentViewModel=ParentViewModel;
}
公共抽象字符串头{get;}
公共抽象IEnumerable节点{get;}
公共抽象IEnumerable GridData{get;}
公共MyTreeViewModel ParentViewModel{get;private set;}
//以下是以标准方式连接到PropertyChanged事件的
公选学校
{
获取{return}isSelected;}
设置
{
_isSelected=值;
RaisePropertyChanged(“IsSelected”);
如果(被选中){
ParentViewModel.SelectedNode=此;
}
}
}
公共布尔展开{get;set;}
}
如您所见,它维护对父视图模型的引用,并且每当IsSelected
设置为true
时,它在父视图模型上将自身设置为SelectedNode
,这将触发DataGrid
sItemsSource
上的数据绑定以刷新
希望这有帮助。我通常会在孩子身上引发一个事件,让家长处理所选项目的关系。回答非常好,谢谢!这就解决了问题,而且效果很好:)
public class MyTreeViewModel : INotifyPropertyChanged // Better to implement this interface in some base class for all your view models
{
private TreeItemViewModelBase _selectedNode;
public IEnumerable<TreeItemViewModelBase> TopLevelNodes
{
get { yield return new TopLevelTreeNodeViewModel(); // Subclass of your base class for tree nodes (ViewModelBase) }
}
public TreeItemViewModelBase SelectedNode
{
get { return _selectedNode; }
set
{
_selectedNode = value;
RaisePropertyChanged("SelectedNode");
}
}
}
<DataGrid Name="dataGrid" ItemsSource="{Binding SelectedNode.GridData}" />
<TreeView Name="treeView" ItemsSource="{Binding TopLevelNodes}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate DataType="{x:Type ViewModel:ViewModelBase}" ItemsSource="{Binding Nodes}">
<TextBlock Text="{Binding Header}" />
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
public abstract class TreeItemViewModelBase : INotifyPropertyChanged
{
private bool _isSelected;
public TreeItemViewModelBase(MyTreeViewModel parentViewModel)
{
ParentViewModel = parentViewModel;
}
public abstract string Header { get; }
public abstract IEnumerable<TreeItemViewModelBase> Nodes { get; }
public abstract IEnumerable GridData { get; }
public MyTreeViewModel ParentViewModel { get; private set; }
// following are hooked up to PropertyChanged event in the standard way
public bool IsSelected
{
get { return _isSelected; }
set
{
_isSelected = value;
RaisePropertyChanged("IsSelected");
if (_isSelected) {
ParentViewModel.SelectedNode = this;
}
}
}
public bool IsExpanded { get; set; }
}