实现Silverlight中DataGrid的双击支持

Silverlight应用程序中,经常需要为DataGrid控件添加双击支持,无论是为了设置单元格的编辑模式,还是为了触发其他事件。本文将详细介绍如何以简单的方式实现这一功能。

目前,有一些尝试在DataGrid上实现双击支持的方法,但它们要么需要额外的依赖,要么实现起来并不简单。本文介绍的方法是通过继承DataGrid控件并扩展它以具有双击钩子的方式来实现的。

使用代码

实现DataGrid非常简单,需要创建一个新的自定义控件,这个控件不是UserControl,而是从DataGrid派生的控件。

XAML代码如下:

<Data:DataGrid x:Class="My.NameSpace.DoubleClickDataGrid" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:Data="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" />

然后是这个控件的代码后台:

using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Shapes; namespace My.NameSpace { public partial class DoubleClickDataGrid : DataGrid { public event RowClickedHandler RowClicked; public event RowDoubleClickedHandler RowDoubleClicked; public delegate void RowClickedHandler(object sender, DataGridRowClickedArgs e); public delegate void RowDoubleClickedHandler(object sender, DataGridRowClickedArgs e); private DataGridRow _LastDataGridRow = null; private DataGridColumn _LastDataGridColumn = null; private DataGridCell _LastDataGridCell = null; private object _LastObject = null; private DateTime _LastClick = DateTime.MinValue; private double _DoubleClickTime = 1500; public double DoubleClickTime { get { return _DoubleClickTime; } set { _DoubleClickTime = value; } } public DoubleClickDataGrid() { InitializeComponent(); this.MouseLeftButtonUp += new MouseButtonEventHandler(DoubleClickDataGridClick); } protected void OnRowClicked() { if (RowClicked != null) { RowClicked(this, new DataGridRowClickedArgs(_LastDataGridRow, _LastDataGridColumn, _LastDataGridCell, _LastObject)); } } protected void OnRowDoubleClicked() { if (RowDoubleClicked != null) { RowDoubleClicked(this, new DataGridRowClickedArgs(_LastDataGridRow, _LastDataGridColumn, _LastDataGridCell, _LastObject)); } } private void DoubleClickDataGridClick(object sender, MouseButtonEventArgs e) { DateTime clickTime = DateTime.Now; DataGridRow currentRowClicked; DataGridColumn currentColumnClicked; DataGridCell currentCellClicked; object currentObject; if (GetDataGridCellByPosition(e.GetPosition(null), out currentRowClicked, out currentColumnClicked, out currentCellClicked, out currentObject)) { bool isDoubleClick = (currentRowClicked == _LastDataGridRow && clickTime.Subtract(_LastClick) <= TimeSpan.FromMilliseconds(_DoubleClickTime)); _LastDataGridRow = currentRowClicked; _LastDataGridColumn = currentColumnClicked; _LastDataGridCell = currentCellClicked; _LastObject = currentObject; if (isDoubleClick) { OnRowDoubleClicked(); } else { OnRowClicked(); } } else { _LastDataGridRow = null; _LastDataGridCell = null; _LastDataGridColumn = null; _LastObject = null; } _LastClick = clickTime; } private bool GetDataGridCellByPosition(Point pt, out DataGridRow dataGridRow, out DataGridColumn dataGridColumn, out DataGridCell dataGridCell, out object dataGridObject) { var elements = VisualTreeHelper.FindElementsInHostCoordinates(pt, this); dataGridRow = null; dataGridCell = null; dataGridColumn = null; dataGridObject = null; if (null == elements || elements.Count() == 0) { return false; } var rowQuery = from gridRow in elements where gridRow is DataGridRow select gridRow as DataGridRow; dataGridRow = rowQuery.FirstOrDefault(); if (dataGridRow == null) { return false; } dataGridObject = dataGridRow.DataContext; var cellQuery = from gridCell in elements where gridCell is DataGridCell select gridCell as DataGridCell; dataGridCell = cellQuery.FirstOrDefault(); if (dataGridCell != null) { dataGridColumn = DataGridColumn.GetColumnContainingElement(dataGridCell); } return dataGridRow != null; } } public class DataGridRowClickedArgs { public DataGridRow DataGridRow { get; set; } public DataGridColumn DataGridColumn { get; set; } public DataGridCell DataGridCell { get; set; } public object DataGridRowItem { get; set; } public DataGridRowClickedArgs(DataGridRow dataGridRow, DataGridColumn dataGridColumn, DataGridCell dataGridCell, object dataGridRowItem) { DataGridRow = dataGridRow; DataGridColumn = dataGridColumn; DataGridCell = dataGridCell; DataGridRowItem = dataGridRowItem; } } }

通过分析点击发生的位置,查看该位置的对象,然后将它们作为事件的一部分返回。

可以像使用DataGrid一样使用这个DoubleClickDataGrid,但可以绑定到RowClicked和RowDoubleClicked事件。例如:

<UserControl x:Class="My.NameSpace.SampleControl" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:Data="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" xmlns:Controls="clr-namespace:My.NameSpace"> <Grid x:Name="LayoutRoot" Background="White"> <Controls:DoubleClickDataGrid x:Name="MyDataGrid" DoubleClickTime="1500" RowClicked="RowClicked" RowDoubleClicked="RowDoubleClick"> <Data:DataGrid.Columns> <Data:DataGridTextColumn Header="MyColumn" CanUserResize="False" CanUserReorder="False" /> </Data:DataGrid.Columns> </Controls:DoubleClickDataGrid> </Grid> </UserControl>

在DoubleClickDataGrid中,将使用标准的DataGrid元素。当行被单击或双击时,它将返回点击的行、单元格、绑定对象和列。可以通过更改DoubleClickTime来改变点击延迟。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485