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

使用 MVVM 通过拖放合并 WPF 工具包 DataGrid 中的两行

starIconstarIconstarIconstarIconstarIcon

5.00/5 (1投票)

2011 年 4 月 20 日

CPOL

2分钟阅读

viewsIcon

30078

downloadIcon

4652

如何使用 MVVM 在 DataGrid 中通过拖放合并两行。

概述

此实现使用 MVVM 在 DataGrid 中通过拖放合并两行。合并逻辑在 ViewModel 中实现。

1. 引言

本文档展示了如何在 DataGrid 中实现行的拖放。详细说明在下文中有提供。与 DataGrid 的拖放功能相关的所有代码都在代码隐藏文件中。为了通过拖放合并 DataGrid 中的两行,本文尝试使用附加依赖属性将行合并逻辑放入 ViewModel 中,从而将 ViewModel 中的 DelegateCommand 绑定到视图中的依赖属性。实现使用了 WPF Toolkit DataGrid [3] 和 WPF Model-View-ViewModel Toolkit [4]

2. 通过拖放合并 DataGrid 中的两行

为了处理 DataGrid 中的拖放,DataGrid 的 XAML 中有一些属性绑定。

<WpfToolkit:DataGrid x:Name="listView" RowHeight="30" 
   ItemsSource="{Binding Path=Items}"
   AutoGenerateColumns="False"
   SelectionMode="Single"
   AllowDrop="True"
   MouseMove="OnMainGridMouseMove"
   localControls:MouseMoveInGridSupport.MouseMoveCommand="{Binding MouseMoveCommand}"   
   localControls:MouseDropInGridSupport.MouseDropCommand="{Binding MouseDropCommand}"

AllowDrop 属性设置为 True,从而启用 DataGrid 中的放置操作。代码隐藏处理程序 OnMainGridMouseMove 处理 MouseMove 事件,该事件检测网格中的鼠标移动,执行 DragDrop,并将控制权传递给其他处理程序。这里没有与 ViewModel 和 Model 相关的业务逻辑或数据。

private void OnMainGridMouseMove(object sender, MouseEventArgs e)
{
   if (e.LeftButton != MouseButtonState.Pressed)
   {
       e.Handled = true;
       return;
   }

   var row = FindVisualParent<DataGridRow>(e.OriginalSource as FrameworkElement);
   if ((row != null) && row.IsSelected)
   {
       var selectedItem = row.Item;
       var finalDropEffect = DragDrop.DoDragDrop(row, selectedItem, DragDropEffects.Move);
       if (finalDropEffect == DragDropEffects.Move)
       {
          e.Handled = false;
       }
   }
}

DataGrid 的 XAML 中有两个附加依赖属性。一个是 MouseMoveInGridSupport

public class MouseMoveInGridSupport : ItemSupportBase
{
    public static ICommand GetMouseMoveCommand(DependencyObject obj)
   {
       return (ICommand)obj.GetValue(MouseMoveCommandProperty);
   }

   public static void SetMouseMoveCommand(DependencyObject obj, ICommand value)
   {
       obj.SetValue(MouseMoveCommandProperty, value);
   }

   public static readonly DependencyProperty MouseMoveCommandProperty =
       DependencyProperty.RegisterAttached("MouseMoveCommand", 
       typeof(ICommand), typeof(MouseMoveInGridSupport), 
       new UIPropertyMetadata(null, new PropertyChangedCallback(OnCommandChanged)));

   private static void OnCommandChanged(DependencyObject sender, 
                       DependencyPropertyChangedEventArgs e)
   {
       if (e.OldValue != null)
          ((ItemsControl)sender).MouseMove -= new MouseEventHandler(OnMouseMoveClick);

       if (e.NewValue != null)
       ((ItemsControl)sender).MouseMove += new MouseEventHandler(OnMouseMoveClick);
   }

   private static void OnMouseMoveClick(object sender, MouseEventArgs e)
   {
       DependencyObject source = (DependencyObject)e.OriginalSource;
       var row = TryFindParent<DataGridRow>(source);
       var item = row.Item;
       if (item == null) return;

       var command = GetMouseMoveCommand((DependencyObject)sender);
       if (command != null)
       {
          if (command.CanExecute(item))
             command.Execute(item);
       }
   }
}

MouseMoveInGridSupport 检测 DataGrid 中发生的 MouseMove 事件,找到相关的 DataGridRow,并将它的 DataItem 传递给 ViewModel 中的 DelegateCommandMouseMoveCommand”。

第二个是 MouseDropInGridSupport

public class MouseDropInGridSupport : ItemSupportBase
{
   public static ICommand GetMouseDropCommand(DependencyObject obj)
   {
       return (ICommand)obj.GetValue(MouseDropCommandProperty);
   }

   public static void SetMouseDropCommand(DependencyObject obj, ICommand value)
   {
       obj.SetValue(MouseDropCommandProperty, value);
   }

   public static readonly DependencyProperty MouseDropCommandProperty =
       DependencyProperty.RegisterAttached("MouseDropCommand", 
       typeof(ICommand), typeof(MouseDropInGridSupport), 
       new UIPropertyMetadata(null, new PropertyChangedCallback(OnMouseDropCommandChanged)));

   private static void OnMouseDropCommandChanged(DependencyObject sender, 
                       DependencyPropertyChangedEventArgs e)
   {
       if (e.OldValue != null)
          ((ItemsControl)sender).Drop -= new DragEventHandler(OnDropClick);

       if (e.NewValue != null)
          ((ItemsControl)sender).Drop += new DragEventHandler(OnDropClick);
   }

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

       var row = TryFindParent<DataGridRow>(source);
       var item = row.Item;

       if (row == null) return;

       var command = GetMouseDropCommand((DependencyObject)sender);
       if (command != null)
       {
          if (command.CanExecute(item))
             command.Execute(item);
       }
   }
}

MouseDropInGridSupport 检测 DataGrid 中发生的 Drop 事件,找到相关的 DataGridRow,并将它的 DataItem 传递给 ViewModel 中的 DelegateCommandMouseDropCommand”。

合并两行的逻辑在 ViewModel 中

public class MainViewModel : ViewModelBase
{
   #region Fields
   private Item dragItem;
   private Item dropItem;
   private DelegateCommand exitCommand;
   public DelegateCommand<Item> MouseMoveCommand { get; private set; }
   public DelegateCommand<Item> MouseDropCommand { get; private set; }
   #endregion

   #region Constructor
   public MainViewModel()
   {
       _items = DataAccess.DataAccess.LoadItems();
       MouseMoveCommand = new DelegateCommand<Item>(MouseMove, CanMouseMove);
      MouseDropCommand = new DelegateCommand<Item>(MouseDrop, CanMouseDrop);
   }
   #endregion

   #region Properties
   IList<Item> _items;
   public IList<Item> Items
   {
       get { return _items; }
       set
       {
          _items = value;
          base.OnPropertyChanged("Items");
       }
   }
   #endregion

   #region Commands
   public ICommand ExitCommand
   {
       get
       {
          if (exitCommand == null)
          {
             exitCommand = new DelegateCommand(Exit);
          }
          return exitCommand;
       }
   } 
   #endregion

   #region Methods
   private void Exit()
   {
       Application.Current.Shutdown();
   }

   private void MouseMove(Item item)
   {
       IList<Item> items = new List<Item>(_items);
       dragItem = item;

       if (dropItem != null && dragItem != null)
       {
          Item newItem = new Item();
          newItem.Name = "Merge row: " + dragItem.Name + " " + dropItem.Name;
          newItem.Data = (dropItem.Data + dragItem.Data) + 100;
          newItem.Id = (dropItem.Id + dragItem.Id) + 100;
          items.Remove(dragItem);
          items.Remove(dropItem);
          items.Add(newItem);
          Items = items;
       }
   }

   private bool CanMouseMove(Item item)
   {
       return true;
   }

   private void MouseDrop(Item item)
   {
       dropItem = item;
   }

   private bool CanMouseDrop(Item item)
   {
       return true;
   }
   #endregion
}

DelegateCommandMouseDropCommand” 获取放置的项目。DelegateCommandMouseDropCommand” 获取移动的项目,然后合并放置和移动的项目。

3. 结论

通过拖放合并网格中的两行是在 MVVM 中实现的。它使用附加依赖属性和 DelegateCommand 将所有合并逻辑放入 ViewModel 中。

4. 参考资料

  1. 常用的 DataGrid 插件:http://code.msdn.microsoft.com/Common-DataGrid-Add-Ons-4f64fcee
  2. MVVM 和 WPF DataGrid:MVVM_DataGrid.aspx
  3. WPF Toolkit DataGrid:http://wpf.codeplex.com/releases/view/40535
  4. WPF Model-View-ViewModel Toolkit:http://wpf.codeplex.com/wikipage?title=WPF%20Model-View-ViewModel%20Toolkit
© . All rights reserved.