Silverlight单元格事件

时间:2021-11-10 19:27:51

 如何给Silverlight的DataGrid单元格添加事件,基本思路有二:

  1、在LoadingRow事件中去添加处理事件,无疑是一个不错的选择

  2、在点击时根据列名和行标识的方法,确定一个单元格是不是也是一个不错的方法呢?

第一种实现方式不用多说。

第十种怎么实现呢?大家肯定会从VisualTreeHelper入手。

VisualTreeHelper得到相应的呈现数据的FrameworkElement无疑是最理想的。

方法是通过 DataGrid->MouseLeftButtonUp->e.OriginalSource然后得到FrameworkElement,最后根据FrameworkElement的DataContext获取数据信息。

问题是如何定位列?根据值比较?貌似不是一个好的方法。

 

我们可以用如下方法:

private void GetGridRowColumnIndex(Point pt, DataGrid grid, out int rowIndex, out int colIndex, out object dataContext)
{
 rowIndex = -1;
 colIndex = -1;
 dataContext = null;
 var elements = VisualTreeHelper.FindElementsInHostCoordinates(pt, grid);
 if (null == elements ||
	elements.Count() == 0)
 { 
  return;
 }

 // Get the rows and columns.
 var rowQuery = from gridRow in elements where gridRow is DataGridRow select gridRow as DataGridRow;
 var cellQuery = from gridCell in elements where gridCell is DataGridCell select gridCell as DataGridCell;
 var cells = cellQuery.ToList<DataGridCell>();
 if (cells.Count == 0)
 {
  return;
 }
			
 foreach (var row in rowQuery)
 {
  dataContext = row.DataContext;
  rowIndex = row.GetIndex();
  foreach (DataGridColumn col in grid.Columns)
  {
   var colContent = col.GetCellContent(row);
   var parent = GetParent(colContent, typeof(DataGridCell));
   if (parent != null)
   {
    var thisCell = (DataGridCell)parent;
    if (object.ReferenceEquals(thisCell, cells[0]))
    {
     colIndex = col.DisplayIndex;
    }
   }
  }
 }
}

private void ProductsGrid_MouseMove(object sender, MouseEventArgs e)
{
 int rowIndex, colIndex;
 object dataContext;
 GetGridRowColumnIndex(e.GetPosition(null), ProductsGrid, out rowIndex, 
   out colIndex, out dataContext);
 SelectedRow.Text = string.Format("[Page={0}], [Row={1}] ", ProductsPager.PageIndex, rowIndex);
 SelectedColumn.Text = string.Format(" [Cell={0}] ", colIndex);
 if (null != dataContext)
 {
  var prod = dataContext as Product;
  ProductInfo.Text = string.Format("[{0}, {1}] ", prod.Name, prod.Color);
 }
}

private FrameworkElement GetParent(FrameworkElement child, Type type)
{
var parent = child.Parent;
if (null != parent)
{
if (parent.GetType() == type)
{
return parent as FrameworkElement;
}
else
{
return GetParent(parent as FrameworkElement, type);
}
}
return null;
}

 

综上所述,用上述方法可以定位到行和列问题搞定收工。

 

后记:为什么放着现成的LoadingRow事件不用而这么搞呢?首先LoadingRow不管用不用都要先挂接事件,造成一定的浪费。

其次:在LoadingRow给控件赋背景颜色值,当有滚动条时,会造成背景颜色逻辑失效(就是有时明明该有的背景因为滚动的原因没了,很是奇怪,有可能是内部的优化,对不呈现的UI元素做优化了,但是没有找到这个问题的合理解决方案),后来就用DataTemplate的绑定方式实现了。

事件处理就用上述方法实现(至于为何当初不用绑定的方法是因为显示列和背景判断列不是同一个,是分离的....)。

 

扩展阅读:http://www.byteblocks.com/post/2010/03/15/How-to-find-selected-row-and-cell-index-in-Silverlight-DataGrid.aspx

程序下载

在相关代码在Views->Home.xaml.cs