当前位置: 首页 > 知识库问答 >
问题:

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

朱海超
2023-03-14

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

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

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

  • Dispacher。BeginInvoke方法:

触发我的命令:

<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 library激活它。

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项目,请在解决方案中添加一个主项目,其中包含一个带有treeview的视图和一个带有将显示在treeview上的ParentViewModel列表的TreeViewModel。定义另一个具有2个viewmodels的项目:一个具有ObservableCollection的类ParentVM和一个childViewModel,使用一个或两个类似于名称的属性,并将其绑定到treeview。在第二个项目中,定义detailsView以查看ChildViewModel的属性。在主项目上,在TreeViewModel中添加SelectedCommandFunction,该函数使用prism激活detailView。(单击父视图时需要有一个详细视图,单击子视图时需要有另一个详细视图。

共有1个答案

夏高朗
2023-03-14

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

防止这种情况的方法:

  1. TreeItemIsSelected直接绑定到虚拟机IsSelected,然后在虚拟机的IsSelected属性上执行操作
  2. 以迂回的方式:在codebehind中,当您处理事件时,检查原始源是否与发送方相同(类似于此处)
  3. 实现自己的EventTrigger,将事件标记为已处理
 类似资料:
  • Am使用带有TreeView控件的WPF XBAP应用程序。Treeview有一个自定义的ItemContainerStyle,并使用分层数据绑定。当我最小化运行XBAP的浏览器并再次最大化它,然后单击TreeView中的一个项目时,该项目没有被选中(即。下面是我在TreeViewItem中使用的样式: 提前谢谢你的帮助。

  • 我正在尝试用multiselect实现一个自定义的。由于我的原因,我不能使用现有的解决方案。 我的问题是:我有一个,其中一些子项被禁用。有时,当我单击启用的节点,然后单击禁用的节点时,父节点会被选中。 我想摆脱这种默认的选择行为,因为我的treeview中的所有项目都有一个数据库属性,我在实际点击项目时设置了这个属性,我不希望treeview自己选择一些项目! 更新:我需要处理对禁用项目的单击,因

  • 我想创建一些表格与自动填充价格在输入框,但我不知道如何实现到我的代码。首先我有选择选项,然后选择选项后,输入框上的价格会自动生成,然后我输入折扣值,然后总价格会自动生成(基本价格-折扣%)。这是我的代码: null null

  • 假设我有一个绑定项目源(可观察集合)的TreeView,我有这样的东西:http://docs.telerik.com/devtools/wpf/controls/radtreeview/how-to/howto-tri-state-mvvm 每个项目包括父视图都有一个复选框和名称(字符串)。 我想让子节点仅在检查父节点时可用。 如果父节点未被选中,所有子节点也将被取消选中。 有没有办法让我做到这

  • 问题内容: 我已经遵循了有关“选择和角度”的出色教程(链接)(代码几乎相同) 这是我的指令: 这是html: 我想要的是,当用户单击编辑按钮时,弹出模式窗口,并在模式窗口中选择在单击编辑按钮之前选择的类别。 这是控制器的一部分: 我已经记录了 $ scope.selectedCategories ,它们一切都很好,但是由于某种原因,在选择中什么都没有选择。 那么我在做什么错了,我该如何解决呢? 编

  • 问题内容: 这是代码: 单击命令按钮时,将调用并执行后备bean中的getDualListModelForTags()。在getDualListModelForTags()中,我做了一些修改,所以我希望更新选择列表。但是,选择列表(id = tags)不会再次呈现。仅当我刷新页面时,才会对选择列表进行修改。 问题答案: PrimeFaces 组件无法与一起使用。您需要使用按钮自己的以ajax为目标