Silverlight 中的双击 DataGrid






4.43/5 (6投票s)
Silverlight 中一个简单的可双击 DataGrid。
引言
本文重点介绍在 Silverlight 的 DataGrid
中实现双击事件的一种简单方法。目前 Silverlight 还不支持双击事件,因此通常需要手动启用它,无论是为了将单元格设置为编辑模式,还是为了触发其他事件。本文详细介绍了如何以简单的方式实现这一点。
背景
已经有一些尝试来启用 DataGrid
的双击支持,其中一些需要额外的依赖项,而另一些则实现起来不够简单。本文的方法是通过继承 DataGrid
控件并扩展它来添加双击钩子,从而创建一个派生控件。
Using the Code
实现数据网格非常简单,只需要创建一个新的自定义控件,该控件不是 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 we've found at least the row,
if (GetDataGridCellByPosition(e.GetPosition(null), out currentRowClicked,
out currentColumnClicked, out currentCellClicked, out currentObject))
{
//And the current row is the same as the last row, and is within
//the timespan, consider it a double-click
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);
}
//If we've got the row, return true -
//sometimes the Column, DataContext could be null
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
来更改单击延迟。
参考文献
本文修改了 Naveen 提供的一种方法,以获取点击的行和数据单元格的位置。 更多信息请阅读
历史
- 2010年10月4日:初始发布