今天需要做 DataGrid 双击后弹出一个窗口的功能。突然发现 DataGrid 这东西很蛋疼,本身不支持也就罢了,还有更恶心的。比如 DataGrid 不能被继承,再比如 DataGridCell 中 Handle 了 MouseLeftButtonDown 事件。
于是,只好走点弯路。自己创建了一个 DataGridHelper
namespace SoftCat.Windows.Controls { using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; public class DataGridHelper { // =================================================================== // 字段 DataGrid _dg; // =================================================================== // 构造与析构 public DataGridHelper(DataGrid dg) { _dg = dg; _dg.LoadingRow += _dg_LoadingRow; } // =================================================================== // 事件处理 void _dg_LoadingRow(object sender, DataGridRowEventArgs e) { e.Row.Loaded += Row_Loaded; } private void Row_Loaded(object sender, RoutedEventArgs e) { DataGridRow row = sender as DataGridRow; foreach (DataGridCell cell in VisualTreeHelperEx.FindChildren<DataGridCell>(row)) { Grid cellGrid = VisualTreeHelper.GetChild(cell, 0) as Grid; cellGrid.MouseLeftButtonDown += cellGrid_MouseLeftButtonDown; } } private void cellGrid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { if (RowMouseLeftButtonDown == null && CellMouseLeftButtonDown == null) return; Grid cellGrid = sender as Grid; DataGridCell cell = VisualTreeHelper.GetParent(cellGrid) as DataGridCell; if (CellMouseLeftButtonDown != null) CellMouseLeftButtonDown(cell, e); if (RowMouseLeftButtonDown != null) { DataGridRow row = VisualTreeHelperEx.FindParent<DataGridRow>(cell); RowMouseLeftButtonDown(row, e); } } // =================================================================== // 扩展事件 public event MouseButtonEventHandler RowMouseLeftButtonDown; public event MouseButtonEventHandler CellMouseLeftButtonDown; } }
上面的这段代码为了突出重点,省去了左键 Up 和右键事件,需要者可以自行添加。
请注意,DataGridCell 的子节点是一个 Grid,我们通过这个 Grid 的 MouseLeftButtonDown 事件捕获到我们需要的行为,然后再转嫁给 DataGridCell 和 DataGridRow。
这是一种投机取巧的行为,但不失为一种万不得已的方法。
此外,上面的代码中使用了我自己写的 VisualTreeHelperEx,代码如下。
namespace SoftCat.Windows { using System; using System.Collections.Generic; using System.Windows; using System.Windows.Media; public static class VisualTreeHelperEx { public static IEnumerable<T> FindChildren<T>(DependencyObject reference) where T : DependencyObject { if (reference == null) throw new ArgumentNullException(); Queue<DependencyObject> q = new Queue<DependencyObject>(); int c = VisualTreeHelper.GetChildrenCount(reference); for (int i = 0; i < c; i++) { DependencyObject o = VisualTreeHelper.GetChild(reference, i); q.Enqueue(o); } while (q.Count > 0) { DependencyObject r = q.Dequeue(); if (r is T) { yield return r as T; } else { c = VisualTreeHelper.GetChildrenCount(r); for (int i = 0; i < c; i++) { DependencyObject o = VisualTreeHelper.GetChild(r, i); q.Enqueue(o); } } } } public static T FindParent<T>(DependencyObject reference) where T : DependencyObject { if (reference == null) throw new ArgumentNullException(); DependencyObject p = reference; do { p = VisualTreeHelper.GetParent(p); if (p is T) { return p as T; } } while (p != null); return null; } } }
希望这篇文章能给您带来一些小小的启发。如果有更好的方法还请告知,谢谢!