65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 MVVM 模式在 WPF 工具包 DataGrid 中检索行标题和单元格

starIconstarIconstarIconstarIconstarIcon

5.00/5 (2投票s)

2011年4月13日

CPOL

2分钟阅读

viewsIcon

37271

downloadIcon

1567

本文档展示了基于数据分组的网格中的行标题实现,以及从基于单元格的网格中检索单元格信息的方法。

1. 引言

本文档展示了基于数据分组的网格中的行标题实现,以及从基于单元格的网格中检索单元格信息的方法。

上述网格中的项目包含两个分组。第一个分组包含值“行标题 1”和“行标题 2”。第二个分组包含值“分组 11”、“分组 12”、“分组 21”和“分组 22”。网格显示基于分组的两个行标题。该网格是基于单元格的。单击单元格时,将弹出一个与单元格信息相关的表单。这需要在单元格上单击鼠标时访问单元格信息。本文档展示了使用 WPF Toolkit DataGrid (http://wpf.codeplex.com/releases/view/40535) 和 MVVM 模式 (http://wpf.codeplex.com/wikipage?title=WPF%20Model-View-ViewModel%20Toolkit) 实现这两个需求。

2. 网格中的行标题

WPF Toolkit 中的 DataGrid 提供了网格中的数据分组。GroupStyle 为行标题创建一个组样式。GroupItem 的模板将行标题描述为 TextBlock,并相应地旋转它。

<GroupStyle>
  <GroupStyle.ContainerStyle>
   <Style TargetType="{x:Type GroupItem}">
     <Setter Property="Margin" Value="0,0,0,0"/>
     <Setter Property="Template">
      <Setter.Value>
        <ControlTemplate TargetType="{x:Type GroupItem}">
         <HeaderedContentControl BorderBrush="#FFA4B97F" BorderThickness="0,0,0,1">
           <HeaderedContentControl.Header>
            <TextBlock FontWeight="Bold" FontSize="12" 
                       Text="{Binding Path=Name}" Margin="5,0,0,0">
              <TextBlock.RenderTransform>
                <RotateTransform Angle="270" /> 
              </TextBlock.RenderTransform>
            </TextBlock>
           </HeaderedContentControl.Header>
           <HeaderedContentControl.Content>
            <ItemsPresenter/>
           </HeaderedContentControl.Content>
         </HeaderedContentControl>
        </ControlTemplate>
      </Setter.Value>
     </Setter>
     <Style.Triggers>
          <DataTrigger Binding="{Binding Name}" Value="Group 11">
            <Setter Property="Template"  Value="{StaticResource defaultGroup}" />
          </DataTrigger>
          <DataTrigger Binding="{Binding Name}" Value="Group 12">
            <Setter Property="Template"  Value="{StaticResource defaultGroup}" />
          </DataTrigger>
          <DataTrigger Binding="{Binding Name}" Value="Group 21">
            <Setter Property="Template"  Value="{StaticResource defaultGroup}" />
          </DataTrigger>
          <DataTrigger Binding="{Binding Name}" Value="Group 22">
            <Setter Property="Template"  Value="{StaticResource defaultGroup}" />
          </DataTrigger>
     </Style.Triggers>
   </Style>
  </GroupStyle.ContainerStyle>
</GroupStyle>

触发器根据行标题名称将标题样式切换为“defaultGroup”。

行标题的多个层级使用 DataGridItemsSource 中描述的多个数据分组,这是一个 CollectionViewSource,具有 GroupDescriptions 来定义组。

<WpfToolkit:DataGrid x:Name="listView" 
            ItemsSource="{Binding Source={StaticResource src}}"  />

<CollectionViewSource x:Key='src' Source="{Binding Items}">
  <CollectionViewSource.GroupDescriptions>
     <PropertyGroupDescription PropertyName="Category1"/>
     <PropertyGroupDescription PropertyName="Category2"/>
  </CollectionViewSource.GroupDescriptions>
</CollectionViewSource>

3. 网格中的单元格检索

使用 DataGrid 将网格设置为基于单元格:SelectionUnit="Cell"。通过处理事件 SelectedCellsChanged: ((Microsoft.Windows.Controls.DataGrid)sender).CurrentCell,在代码后置中检索单元格信息。但 WPF MVVM 只将与视图相关的代码放在代码后置中。业务逻辑应该在 ViewModel 中。将事件处理程序移动到 ViewModel 的一种方法是使用附加依赖属性,它将 ViewModel 中的 Command 绑定到 View 中的依赖属性。

DataGridItemsHelper 类将 ICommand 注册为 DataGridMouseUp 事件的命令依赖属性,并将选定的 DataGridRowDataGridCell 传递给 Command 处理程序。

public class DataGridItemsHelper
{
      public static readonly DependencyProperty CommandProperty = 
        DependencyProperty.RegisterAttached("Command", typeof(ICommand), 
        typeof(DataGridItemsHelper), 
        new UIPropertyMetadata(null, new PropertyChangedCallback(OnCommandChanged)));

      public static ICommand GetCommand(DependencyObject obj)
      {
             return (ICommand)obj.GetValue(CommandProperty);
      }

      public static void SetCommand(DependencyObject obj, ICommand value)
      {
             obj.SetValue(CommandProperty, value);
      }

      private static void OnCommandChanged(DependencyObject sender, 
                          DependencyPropertyChangedEventArgs e)
      {
             if (e.OldValue != null)
                   ((ItemsControl)sender).MouseUp -= 
                       new MouseButtonEventHandler(OnMouseUpClick);

             if (e.NewValue != null)
                   ((ItemsControl)sender).MouseUp += 
                       new MouseButtonEventHandler(OnMouseUpClick);
      }

      private static void OnMouseUpClick(object sender, MouseButtonEventArgs e)
      {
             DependencyObject source = (DependencyObject)e.OriginalSource;

             var row = TryFindParent<DataGridRow>(source);
             var cell = TryFindParent<DataGridCell>(source);
             if (cell == null || row == null ) return;
             var command = GetCommand((DependencyObject)sender);
             if (command != null)
             {
                   if (command.CanExecute(new DataGridItem(row, cell)))
                         command.Execute(new DataGridItem(row, cell));
             }
      }

      public static T TryFindParent<T>(DependencyObject child)
        where T : DependencyObject
      {
             DependencyObject parentObject = GetParentObject(child);
             if (parentObject == null) return null;
             T parent = parentObject as T;
             if (parent != null)
             {
                   return parent;
             }
             else
             {
                   return TryFindParent<T>(parentObject);
             }
      }

      public static DependencyObject GetParentObject(DependencyObject child)
      {
             if (child == null) return null;
             ContentElement contentElement = child as ContentElement;

             if (contentElement != null)
             {
                   DependencyObject parent = ContentOperations.GetParent(contentElement);
                   if (parent != null) return parent;

                   FrameworkContentElement fce = contentElement as FrameworkContentElement;
                   return fce != null ? fce.Parent : null;
             }
             return VisualTreeHelper.GetParent(child);
      }
}

DataGrid 中的依赖属性“Command”将 ViewModel 中的命令属性“CellClickCommand”绑定到 DataGrid 单元格中的 OnMouseUp 事件。

utils:DataGridItemsHelper.Command = "{Binding CellClickCommand}" 

CellClickCommand”是 ViewModel 中的一个委托命令,它将所选单元格的 DataGridRowDataGridCell 传递给命令处理程序。

public DelegateCommand<DataGridItem> CellClickCommand { get; private set; }

CellClickCommand = new DelegateCommand<DataGridItem>(
                       CellClickSelection, CanCellClickSelection);

private void CellClickSelection(DataGridItem item)
{
      MessageBox.Show("Cell's column is " + 
                      item.Gridcell.Column.Header.ToString() +
                      " it's ID is " + 
                      ((RowHeaderGrid.Models.Item)(item.Gridrow.Item)).ID);
}

4. 结论

此实现为基于数据分组的行标题以及使用 MVVM 模式在 WPF Toolkit DataGrid 中检索单元格提供了一种解决方案。

© . All rights reserved.