
March 15, 2010 11:05 by
Naveen
Download Sample Projects (116.00 kb)
Some back I wrote about
How to customize display of columns in DataGrid in silverlight application. But this customization
was limited to accessing DataGridRow and changing of style as a whole. Recently I have come across
lot of questions about knowing what row and what cell was accessed by user and other related questions. So
this post is about addressing some of the following questions.
- How to find row and cell index of user selection in DataGrid?
- How to find row and column index of mouse click in Silverlight datagrid?
- How to find row and column index of datagrid depending on mouse click?
I thought this was going to be a stright forward excercise. I was expecting some kind of direct
method or property on some event that I could access to answer the question. It turned out
that half of this question could be answered directly by using GetIndex method on
DataGridRow object. But I could not get direct answer to index of cell that a
user selected in datagrid. A lot of answers that I found revolved around adding a event handler for
mouse events in the template for a given DataGridColumn. That meant that I will have to
attach these event handlers to all the columns. Then the question was what if I added the columns
dynamically or some other custom implementation.
Coming from classic Win32 and MFC background, I thought there has to be some kind of
API that I could use where I could capture moust position and do some kind of hit test to
find out location of mouse click or mouse move position. After digging around the APIs, I found
VisualTreeHelper class that gave me what I was looking for. Following code snippet shows
how I was able to get the column and row index inside DataGrid where moust position was.
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);
}
}
You can download the attached project to see the whole code in action. The implementation is in
Home.xaml/cs