【问题标题】:Get selected TreeViewItem in MVVM在 MVVM 中获取选定的 TreeViewItem
【发布时间】:2013-09-27 23:34:00
【问题描述】:

我想制作带有可编辑节点的 TreeView。我在谷歌上搜索了这篇不错的文章:

http://www.codeproject.com/Articles/31592/Editable-TextBlock-in-WPF-for-In-place-Editing

但我有一个问题。我的 TreeView 动态地形成,而不是像北极那样静态地形成。就这样

    <TreeView Name="_packageTreeView" Margin="5" ItemsSource="{Binding PackageExtendedList}">
         <TreeView.InputBindings>
             <KeyBinding Key="C" Command="{Binding *TestCommand*}" CommandParameter="{Binding}" />
         </TreeView.InputBindings>
         <i:Interaction.Triggers>
             <i:EventTrigger EventName="SelectedItemChanged">
                 <i:InvokeCommandAction Command="{Binding PackageTreeItemChangeCommand}" CommandParameter="{Binding ElementName=_packageTreeView, Path=SelectedItem}"/>
             </i:EventTrigger>
         </i:Interaction.Triggers>
         <TreeView.ItemContainerStyle>
             <Style TargetType="{x:Type TreeViewItem}">
                 <Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay}" />
             </Style>
         </TreeView.ItemContainerStyle>
         <TreeView.ItemTemplate>
             <HierarchicalDataTemplate DataType="{x:Type MasterBuisnessLogic:RootDocPackage}" ItemsSource="{Binding Path=Childs}">
                 <Grid>
                     <Grid.ColumnDefinitions>
                         <ColumnDefinition>
                         </ColumnDefinition>
                         <ColumnDefinition>
                         </ColumnDefinition>
                     </Grid.ColumnDefinitions>
                    <Image Source="/Resources/DocGroup.png"></Image>
                    <Etb:EditableTextBlock Margin="5,0,0,0" Grid.Column="1" Text="{Binding Path=Name}"></Etb:EditableTextBlock>
                 </Grid> 
             </HierarchicalDataTemplate>
         </TreeView.ItemTemplate>
     </TreeView>

PackageExtendedList - DocPackageExtended 列表。

那么,第一个问题 - 如何在 TestCommand 中获取 TreeViewItem 实例?不是实例 DocPackageExtended 类!我想像文章中那样选择实例 TreeViewItem。

第二个问题 - 在我获得实例 TreeViewItem 后,如何从 TreeView 项的 DataTemplate 中获得 EditableTextBlock。

添加答案

我已经试过了。因为在 MVVM ViewModel 中不能有任何链接到像 TreeView 这样的 View 对象,我在代码隐藏中制作处理程序,就像那样

private void TreeViewItemSelected(object sender, RoutedEventArgs e)
{
    // Already have TreeViewItem instance without of ItemContainerGenerator help
    var tvi = e.OriginalSource as TreeViewItem;

    if (tvi == null)
        return;

    var etb = VisualTreeLib.VisualTreeLib.GetVisualChild<EditableTextBlock>(tvi);
    if (etb == null)
        return;

    // Do what I want
    etb.IsEditable = true;
}

不幸的是,这没有任何影响:(

我也尝试过这种方法,但也失败了。

在 DocPackageExtended 类型中我定义了属性

public bool IsEditable
{
    get { return _isEditable; }
    set
    {
        _isEditable = value;
        OnPropertyChanged(new PropertyChangedEventArgs("IsEditable"));
    }
}

比 XAML 中的变化:

<Etb:EditableTextBlock Margin="5,0,0,0" Grid.Column="1" Text="{Binding Path=Name}" *IsEditable="{Binding Path=IsEditable}"*/>

在 ViewModel 中

private void TestCommandMethod(object obj)
{
    var dpe = obj as DocPackageExtended;
    if (dpe == null)
       return;
    dpe.IsEditable = true;
}

也不行:( 有什么想法吗?

【问题讨论】:

    标签: wpf mvvm datatemplate treeviewitem


    【解决方案1】:

    这可能会对你有所帮助。

    private void Button_Click(object sender, RoutedEventArgs e)
        {
            TreeViewItem treeViewItemFound = GetItem(MyTreeview, MyTreeview.SelectedItem);
            ContentPresenter header = treeViewItemFound.Template.FindName("PART_Header", treeViewItemFound) as ContentPresenter;
            if (header != null)
            {
                TextBox myTextBox = (TextBox)header.ContentTemplate.FindName("MyTextBox", header);
            }
        }
    
        public TreeViewItem GetItem(ItemsControl container, object itemToSelect)
        {
            foreach (object item in container.Items)
            {
                if (item == itemToSelect)
                {
                    return (TreeViewItem)container.ItemContainerGenerator.ContainerFromItem(item);
                }
                else
                {
                    ItemsControl itemContainer = (ItemsControl)container.ItemContainerGenerator.ContainerFromItem(item);
                    if (itemContainer.Items.Count > 0)
                    {
                        TreeViewItem treeViewItemFound = GetItem(itemContainer, itemToSelect);
                        if (treeViewItemFound != null)
                            return treeViewItemFound;
                    }
                }
            }
    
            return null;
        }
    

    【讨论】:

      【解决方案2】:

      第一个问题:由于似乎可以选择多个条目,所以需要在TestCommand的执行方法中过滤所有选择的条目:

      IEnumerable<DocPackageExtended> selectedEntries = PackageExtendedList.Where(d => d.IsSelected);
      

      如果禁用了多选,您可以将 TreeView 的选定项绑定到 VM 中的一个属性,并在 TestCommand 的方法中访问该属性。

      第二个问题:你通过var container = YourTreeViewInstance.ItemContainerGenerator.ContainerFromItem(dataInstance);获取dataitem的容器。现在你必须在VisualTreeHelper 的帮助下遍历这个容器,直到找到EditableTextBlock 类型的控件。但我不会在 ViewModel 中执行此操作,而是在辅助类中或在附加属性的帮助下执行此操作。

      编辑:您将 DocPackageExtended 类的 Childs 属性中的实例的 IsEditable 属性绑定到 EditableTextBox,但在您的 TestCommandMethod 中,您正在操作 DocPackageExtended 实例的 IsEditableproperty直接地。您可以执行以下操作:

      private void TestCommandMethod(object obj)
      {
          var dpe = obj as DocPackageExtended;
          if (dpe == null)
             return;
          dpe.IsEditable = true;
          foreach (RootDocPackage rdp in dpe.Childs)
          {
              rdp.IsEditable = true;
          }
      }
      

      【讨论】:

      • 我在第一篇文章中添加了答案,以便能够格式化代码,看。你如何在文本中制作灰色背景?找不到。
      • 我假设 TestCommand 中的 CommandParameter 是 ViewModel 本身,而不是 DocPackageExtended-instance,因此对话始终返回 null。如果是这样,请查看我的编辑。
      • CommandParameter 具有正确的类型对象 (DocPackageExtended),在调试器下检查。不允许多选。
      猜你喜欢
      • 2012-02-26
      • 2014-08-07
      • 1970-01-01
      • 2011-07-10
      • 2011-02-04
      • 1970-01-01
      • 2013-07-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多