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

Silverlight 中的双击 DataGrid

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.43/5 (6投票s)

2010年10月4日

CPOL

1分钟阅读

viewsIcon

50585

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,但您可以绑定到 RowClickedRowDoubleClicked 事件。

例如

<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日:初始发布
© . All rights reserved.