Проблема с привязкой выбранного элемента сетки данных к выбранному значению древовидной структуры - PullRequest
1 голос
/ 07 сентября 2010

У меня проблемы с привязкой древовидного представления к выбранному элементу сетки данных.

они находятся в разных представлениях, но выбранный элемент решетки данных уже передан связанной модели представления дерева.В связанной модели представления дерева есть свойство SelectedGroup, которое представляет собой выбранный элемент таблицы данных, а его тип - Group.Я хочу привязать поле идентификатора группы к древовидному представлению, то есть хочу, чтобы идентификатор выбранного элемента был выбран в древовидном представлении, а также обновлен с помощью выбранного значения древовидного представления.Я не мог узнать, как связать.Вот скелет моего дерева, который может просто иерархически перечислять все группы.Может ли кто-нибудь помочь мне заполнить необходимые поля, пожалуйста?Заранее спасибо.

    <TreeView Grid.Column="1" Grid.Row="4" Height="251" HorizontalAlignment="Left"
        Margin="4,3,0,0" Name="parentGroupTreeView" VerticalAlignment="Top" 
        Width="246" ItemsSource="{Binding Groups}" ItemContainerStyle="{x:Null}"  
        SelectedValuePath="ID">
            <TreeView.ItemTemplate>
                <HierarchicalDataTemplate ItemsSource="{Binding 
                 Converter={x:Static Member=conv:GroupSubGroupsConv.Default}}">
                    <Label Name="groupLabel" Content="{Binding GroupName}"/>
                </HierarchicalDataTemplate>
            </TreeView.ItemTemplate>                
        </TreeView>

1 Ответ

1 голос
/ 07 сентября 2010

Начните с просмотра следующей статьи Джоша Смита о Упрощение WPF TreeView с помощью шаблона ViewModel .

Я также использую DataGrid из инструментария WPF.

Чтобы понять, как работает этот код, посмотрите на свойство IsSelected ниже.

Вот XAMLкоторый содержит дерево и сетку данных:

<Window x:Class="TreeviewDatagrid.Views.MainView"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:WpfToolkit="clr-namespace:Microsoft.Windows.Controls;assembly=WPFToolkit" 
  xmlns:ViewModels="clr-namespace:TreeviewDatagrid.ViewModels" Title="Main Window" Height="400" Width="800">
  <DockPanel>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="3*"/>
            <ColumnDefinition Width="7*"/>
        </Grid.ColumnDefinitions>
        <TreeView ItemsSource="{Binding Groups}"
                  Grid.Column="0">
            <TreeView.ItemContainerStyle>
                <Style TargetType="{x:Type TreeViewItem}">
                    <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
                    <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
                    <Setter Property="FontWeight" Value="Normal" />
                    <Style.Triggers>
                        <Trigger Property="IsSelected" Value="True">
                            <Setter Property="FontWeight" Value="Bold" />
                        </Trigger>
                    </Style.Triggers>
                </Style>
            </TreeView.ItemContainerStyle>
            <TreeView.Resources>
                <HierarchicalDataTemplate 
                    DataType="{x:Type ViewModels:GroupViewModel}" 
                    ItemsSource="{Binding Children}" >
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="{Binding GroupName}" />
                    </StackPanel>
                </HierarchicalDataTemplate>
            </TreeView.Resources>
        </TreeView>
        <WpfToolkit:DataGrid  
            Grid.Column="1"
            SelectedItem="{Binding Path=SelectedGroup, Mode=TwoWay}"
            ItemsSource="{Binding Path=Groups, Mode=OneWay}" >
        </WpfToolkit:DataGrid>
    </Grid>
  </DockPanel>
</Window>

Вот модель основного представления, с которой связываются TreeView и DataGrid:

using System.Collections.Generic;
using System.Collections.ObjectModel;
using TreeviewDatagrid.Models;

namespace TreeviewDatagrid.ViewModels
{
 public class MainViewModel : ViewModelBase
 {
  public MainViewModel()
  {
     Group g1 = new Group();
     g1.Id = 1;
     g1.GroupName = "Planners";
     g1.Description = "People who plan";
     GroupViewModel gvm1 = new GroupViewModel(this, g1);

     Group g2 = new Group();
     g2.Id = 2;
     g2.GroupName = "Thinkers";
     g2.Description = "People who think";
     GroupViewModel gvm2 = new GroupViewModel(this, g2);

     Group g3 = new Group();
     g3.Id = 3;
     g3.GroupName = "Doers";
     g3.Description = "People who do";
     GroupViewModel gvm3 = new GroupViewModel(this, g3);

     IList<GroupViewModel> list = new List<GroupViewModel>();
     list.Add(gvm1);
     list.Add(gvm2);
     list.Add(gvm3);

     _selectedGroup = gvm1;

     _groups = new ReadOnlyCollection<GroupViewModel>(list);
  }

  readonly ReadOnlyCollection<GroupViewModel> _groups;
  public ReadOnlyCollection<GroupViewModel> Groups
  {
     get { return _groups; }
  }

  private GroupViewModel _selectedGroup;
  public GroupViewModel SelectedGroup
  {
     get
     {
        return _selectedGroup;
     }
     set
     {
        // keep selection in grid in-sync with tree
        _selectedGroup.IsSelected = false;
        _selectedGroup = value;
        _selectedGroup.IsSelected = true;
        OnPropertyChanged("SelectedGroup");
     }
  }

  public void ChangeSelectedGroup(GroupViewModel selectedGroup)
  {
     _selectedGroup = selectedGroup;
     OnPropertyChanged("SelectedGroup");
  }
 }
}

Вот модель представления, которую я использую для привязки ксетка и дерево:

using TreeviewDatagrid.Models;

namespace TreeviewDatagrid.ViewModels
{
   public class GroupViewModel : TreeViewItemViewModel
   {
      private readonly MainViewModel _mainViewModel;
      readonly Group _group;
      bool _isSelected;

      public GroupViewModel(MainViewModel mainViewModel, Group group) : base(null, true)
      {
         _mainViewModel = mainViewModel;
         _group = group;
      }

      public string GroupName
      {
         get { return _group.GroupName; }
      }

      public override bool IsSelected
      {
         get { return _isSelected; }
         set
         {
            if (value != _isSelected)
            {
               _isSelected = value;
               if (_isSelected )
               {
                  // keep tree selection in sync with grid
                  _mainViewModel.ChangeSelectedGroup(this);
               }
               this.OnPropertyChanged("IsSelected");
            }
         }
      }

      protected override void LoadChildren()
      {
        // load children in treeview here
      }
   }
}

Для полноты здесь приведен объект Group:

  namespace TreeviewDatagrid.Models
  {
     public class Group
     {
        public int Id  { get; set; }
        public string GroupName { get; set; }
        public string Description { get; set; }
     }
  }

, а также базовый класс для TreeView:

using System.Collections.ObjectModel;
using System.ComponentModel;

namespace TreeviewDatagrid.ViewModels
{
   /// <summary>
   /// Base class for all ViewModel classes displayed by TreeViewItems.  
   /// This acts as an adapter between a raw data object and a TreeViewItem.
   /// </summary>
   public class TreeViewItemViewModel : INotifyPropertyChanged
   {
       #region Data

       static readonly TreeViewItemViewModel DummyChild = new TreeViewItemViewModel();

       readonly ObservableCollection<TreeViewItemViewModel> _children;
       readonly TreeViewItemViewModel _parent;

       bool _isExpanded;
       bool _isSelected;

       #endregion // Data

       #region Constructors

       protected TreeViewItemViewModel(TreeViewItemViewModel parent, bool lazyLoadChildren)
       {
           _parent = parent;

           _children = new ObservableCollection<TreeViewItemViewModel>();

           if (lazyLoadChildren)
               _children.Add(DummyChild);
       }

       // This is used to create the DummyChild instance.
       private TreeViewItemViewModel()
       {
       }

       #endregion // Constructors

       #region Presentation Members

       #region Children

       /// <summary>
       /// Returns the logical child items of this object.
       /// </summary>
       public ObservableCollection<TreeViewItemViewModel> Children
       {
           get { return _children; }
       }

       #endregion // Children

       #region HasLoadedChildren

       /// <summary>
       /// Returns true if this object's Children have not yet been populated.
       /// </summary>
       public bool HasDummyChild
       {
           get { return this.Children.Count == 1 && this.Children[0] == DummyChild; }
       }

       #endregion // HasLoadedChildren

       #region IsExpanded

       /// <summary>
       /// Gets/sets whether the TreeViewItem 
       /// associated with this object is expanded.
       /// </summary>
       public bool IsExpanded
       {
           get { return _isExpanded; }
           set
           {
               if (value != _isExpanded)
               {
                   _isExpanded = value;
                   this.OnPropertyChanged("IsExpanded");
               }

               // Expand all the way up to the root.
               if (_isExpanded && _parent != null)
                   _parent.IsExpanded = true;

               // Lazy load the child items, if necessary.
               if (this.HasDummyChild)
               {
                   this.Children.Remove(DummyChild);
                   this.LoadChildren();
               }
           }
       }

       #endregion // IsExpanded

       #region IsSelected

       /// <summary>
       /// Gets/sets whether the TreeViewItem 
       /// associated with this object is selected.
       /// </summary>
       public virtual bool IsSelected
       {
           get { return _isSelected; }
           set
           {
               if (value != _isSelected)
               {
                   _isSelected = value;
                   this.OnPropertyChanged("IsSelected");
               }
           }
       }

       #endregion // IsSelected

       #region LoadChildren

       /// <summary>
       /// Invoked when the child items need to be loaded on demand.
       /// Subclasses can override this to populate the Children collection.
       /// </summary>
       protected virtual void LoadChildren()
       {
       }

       #endregion // LoadChildren

       #region Parent

       public TreeViewItemViewModel Parent
       {
           get { return _parent; }
       }

       #endregion // Parent

       #endregion // Presentation Members

       #region INotifyPropertyChanged Members

       public event PropertyChangedEventHandler PropertyChanged;

       protected virtual void OnPropertyChanged(string propertyName)
       {
           if (this.PropertyChanged != null)
               this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
       }

       #endregion // INotifyPropertyChanged Members
   }
}
...