用户更新选定的子WPF命令后,TreeView自动选择父级

时间:2017-11-15 10:26:43

标签: c# wpf xaml treeview

我有一个2级WPF树视图。当我单击子项时,会触发正确的selectedCommand并且一切正常。

但是当我点击我的详细信息视图并更新此选定项目的字段时,它会取消选择我的childItem并触发父命令,因为父项已被选中,但我需要保持我的childItem被选中。

我找到了一些关于同一问题的主题,但我使用命令进行绑定,而不仅仅是代码隐藏,所以我不知道如何让这个解决方案适合我。

触发我的命令:

<i:Interaction.Triggers>
    <i:EventTrigger EventName="SelectedItemChanged">
        <i:InvokeCommandAction
            Command="{Binding ItemSelectedCommand}"
            CommandParameter="{Binding SelectedItem, ElementName=TreeView}"/>
    </i:EventTrigger>
</i:Interaction.Triggers>

我的树视图:

<TreeView x:Name="TreeView"
        ItemsSource="{Binding Modules}">
    <HierarchicalDataTemplate DataType="{x:Type module:ParentViewModel}" ItemsSource="{Binding ChildItems}">
        <TextBlock Text="Parent"/>
    </HierarchicalDataTemplate>

    <HierarchicalDataTemplate DataType="{x:Type module:ChildViewModel}">
        <TextBlock Text="{Binding Path=childName}"/>
    </HierarchicalDataTemplate>                  
</TreeView>

这是我的命令,它在我的ViewModel文件中

public ICommand ItemSelectedCommand
{
   get
   {
        return _itemSelectedCommand ?? (_itemSelectedCommand = new CommandHandler(param => SelectedCommand(param)));
   }
}

public void SelectedCommand(object selectedItem)
{
     //code to activate my details view with prism
    if(selectedItem.GetType().Name == "ParentType")
    { 
        ActivateParentView(); 
    }
    else 
    {
        ActivateDetailsView(.....); //activate child view
    }
}

因此,当我在树视图中选择一个项目时触发相同的命令,但是当我选择子项时,父事件也会被触发,因此我的命令被触发2次并激活我的父视图并且不会停留在我的孩子看来。如果我已通过子命令,如何停止传播事件?如何使用我的命令而不是后面的代码?

编辑

这是我的函数ActivateDetailsView(),由我的SelectedCommand调用 我有13个模块,每个模块都有一个detailsView,所以当我点击我选择的项目时,我将使用反射性搜索我需要激活的视图,并使用PRISM库来激活它。

private void ActivateDetailsView(string nameTypeItem,IRegion tabConfigurationRegion, ModuleItemBaseViewModel selectedItem)
    {
        try
        {
            string viewName = "ModuleItem" + nameTypeItem + "DetailsView";

            string moduleName = "Module" + nameTypeItem;
            string fullViewName = moduleName + ".Views." + viewName + ", " + moduleName;

            var typeOfCurrentView = Type.GetType(fullViewName);
            //var view = Activator.CreateInstance(typeOfCurrentView);
            var view = tabConfigurationRegion.GetView(viewName);
            if (view == null)
            {
                view = _container.Resolve(typeOfCurrentView);

                // Add the view to the main region. This automatically activates the view too.
                tabConfigurationRegion.Add(view, viewName);
            }

            // The view has already been added to the region so just activate it.
            tabConfigurationRegion.Activate(view);

            string viewModelName = "ModuleItem" + nameTypeItem + "DetailsViewModel";
            string fullViewModelName = moduleName + ".ViewModels." + viewModelName + ", " + moduleName;

            var typeOfCurrentViewModel = Type.GetType(fullViewModelName);
            //equivalent to ModuleItemSiemensDetailsViewModel viewModelM = view.DataContext as ModuleItemSiemensDetailsViewModel;
            var propertyInfoDataContext = view.GetType().GetProperty("DataContext");
            var viewModelModuleItem = propertyInfoDataContext.GetValue(view, null);

            if (viewModelModuleItem != null)
            {
                PropertyInfo prop = typeOfCurrentViewModel.GetProperty("CurrentModuleItem");

                //equivalent to viewModelModuleItem.CurrentModuleItem = selectedItem as ModuleItemBaseViewModel;
                prop.SetValue(viewModelModuleItem, selectedItem, null);
            }
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex.Message);
            Debug.WriteLine(ex.StackTrace);
        }
    }

重现问题:启动一个新的WPF项目,在解决方案中添加一个主项目,其中包含一个带树视图的视图和一个treeviewviewmodel,其中包含将在您的树视图中显示的ParentViewModel列表。使用2个视图模型定义另一个项目:一个具有ObservableCollection的类ParentVM和一个childViewModel,让一个或两个属性像name一样,并将其绑定到treeview。在第二个项目中,定义detailsView以查看ChildViewModel的属性。在您的主项目中,在treeviewviewmodel中添加一个SelectedCommandFunction,它使用prism来激活您的detailView。 (单击Parent时需要有一个DetailsView,单击ChildView时需要另一个。

1 个答案:

答案 0 :(得分:0)

每个TreeViewItem都在其父级的可视树中,并且事件将向下冒泡,因此如果您单击树叶,并且它有两个父级,则该事件将被调用3次。

防止这种情况的方法:

  1. IsSelected的{​​{1}}直接绑定到您的VM的TreeItem,并执行您的VM的IsSelected属性OnPropertyChanged
  2. 以迂回的方式:在代码隐藏中,当您处理事件时,检查IsSelected是否与发件人相同(类似于here
  3. Implement your own EventTrigger that marks events as Handled