Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Wpf 从另一个控件的HierarchycalDataTemplate设置一个控件的属性_Wpf_Datagrid_Treeview_Binding - Fatal编程技术网

Wpf 从另一个控件的HierarchycalDataTemplate设置一个控件的属性

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; } //

我有这样一个viewmodel:

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”。我如何让它工作,我做错了什么?

以下是我通常针对这种情况的解决方案:

  • 首先,我总是有一个包含根节点集合的VM。让我们把它命名为
    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
    s
    ItemsSource
    上的数据绑定以刷新


    希望这有帮助。

    我通常会在孩子身上引发一个事件,让家长处理所选项目的关系。回答非常好,谢谢!这就解决了问题,而且效果很好:)
    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; }
    }