Hi
In our MouseDown event we want to determine and store which cell was clicked on for processing later (after mouseup, double click etc.)
In normal circumstances it is straightforward - we just use Grid.DisplayLayout.UIElement.ElementFromPoint and use GetContext(typeof(UltraGridCell)) to get the associated cell object.
However if the Cell is merged with some of it's siblings by using the column.MergedCellStyle then the cell returned by GetContext is the first cell in the merged cells not the cell under the mouse point.
Initially I thought I could look at that cell's UIElement and work out which direction the cell that contains the clicked point is by comparing it's Rect and the mouse point. However this is not always possible because the first cell might not be visible if it is scrolled off of the top of the grid hence it doesn't have an associated UIElement.
I notice that a MergedCellUIElement is available in the UIElement hierarchy from the clicked point which contains a list of CellUIElements it spans (in a property called CellElements). If we could access this it would at least be a smaller subset to hittest with the mouse point. However this property is not public. Ah and a useful function called GetCellElemFromPoint is also private, which looking at the source code does exactly that.
The only solution I can see is to scan the UIElement of _every_ cell in the column the returned cell belongs to in order to find the one that contains the clicked point. However this only works for me because I know that I only enable MergedCellStyle on a column. If it was enabled on the whole grid (so they could be merged horizontally aswell) then I would have to search the entire grid to find the target cell, creating cell objects for all cells included in the search that haven't been displayed.
Is there a better way to do this?
(Really I would expect this to be easily available from the grid or griduielement - the fact the UIElement is a merged cell is an implementation detail that I shouldn't have to be concerned about in order to figure out which row/column/cell has been clicked on)
Thanks again
Martin
Hi Martin,
One easy thing you could do is take advantage of the fact the ActiveRow of the grid is set before the MouseDown event fires. So you can check to see if the cell you get is in the ActiveRow and if not, get the cell from the same column in the ActiveRow. Like so:
private void ultraGrid1_MouseDown(object sender, MouseEventArgs e) { UltraGrid grid = (UltraGrid)sender; UIElement lastElementEntered = grid.DisplayLayout.UIElement.LastElementEntered; UltraGridCell cell = lastElementEntered.GetContext(typeof(UltraGridCell)) as UltraGridCell; if (cell != null) { if (cell.Row != grid.ActiveRow) { cell = grid.ActiveRow.Cells[cell.Column]; } } }
Is it the case that the ActiveRow is set when I click with the right mouse button? Doesn't seem to be...
However it appears that calling GetContext(cell) on the UIElement returned from LastElementEntered does return the actual cell that was clicked on, not the first cell in the merged group.
So the solution seems to be to use LastElementEntered rather than the UIElement returned by ElementFromPoint. Do you think this will be the case in all circumstances?
Thanks,
jonesmar said:Is it the case that the ActiveRow is set when I click with the right mouse button? Doesn't seem to be...
No, you didn't mention the mouse button, so I assumed it was the left.
jonesmar said:However it appears that calling GetContext(cell) on the UIElement returned from LastElementEntered does return the actual cell that was clicked on, not the first cell in the merged group. So the solution seems to be to use LastElementEntered rather than the UIElement returned by ElementFromPoint. Do you think this will be the case in all circumstances?
Hm, that's odd. So the element being returned from LastElementEntered must be a different element than the one you are getting from ElementFromPoint. I don't understand why that would be the case, unless it's because there are two elements overlapping in the same place and LastElementEntered is not being set by the MergedCellUIElement which is on top. That's a little weird and may be a bug, so I'm not entirely sure that you should rely on it. On the other hand, the only other way I can thikn of to get this to work would be to walk up to the RowCellAreaUIElement and loop through it's child elements collection for each RowUIElement and see which one contains the current mouse position. Once you have the row the mouse is in, you can get the correct the cell.
You are probably right that there should be an easier way. You should Submit a feature request to Infragistics that they add a GetCellFromPoint method that takes care of all of this stuff for you and accounts for merged cells.
Hi Mike,
Thanks for the prompt response.
Using the code you sent and moving my call to set the active row within the MouseDown event fixes my problem.
Thank you.
Annie
Hi,
MergedCells make things more complicated. I hadn't thought of that. :)
Here's some code that should handle all cases, though.
private UltraGridRow GetRowFromPoint(UltraGrid grid, Point p) { UIElement element = grid.DisplayLayout.UIElement.ElementFromPoint(p); if (element == null) return null; RowColRegionIntersectionUIElement rowColRegionIntersectionUIElement = element.GetAncestor(typeof(RowColRegionIntersectionUIElement)) as RowColRegionIntersectionUIElement; if (rowColRegionIntersectionUIElement == null) return null; foreach (UIElement childElement in rowColRegionIntersectionUIElement.ChildElements) { RowUIElement rowUIElement = childElement as RowUIElement; if (rowUIElement == null) continue; if (rowUIElement.Rect.Contains(p)) { return rowUIElement.Row; } } return null; }
Hi again,
This is the method I am using to try to get to the cell. My issue is similar. I listen to the grid's click event and from this event, I raise my own RowClick or RowRightClick. If the user right clicks on a cell, I want to set the row as the active one.
With the following code, I am able to get the right row and cell using the "ElementFromPoint" method and the right row is being set as the active one.
Infragistics.Win.UIElement element = ultraGrid1.DisplayLayout.UIElement.ElementFromPoint(m_lastMouseDownX, m_lastMouseDownY);
UltraWinGrid.UltraGridRow row = null;
UltraWinGrid.UltraGridCell cell = null;
try
{
row = (UltraWinGrid.UltraGridRow)element.GetContext(typeof(UltraWinGrid.UltraGridRow));
//trigger either the RowClick or RowRightClick events
if (row != null)
cell = (UltraWinGrid.UltraGridCell)element.GetContext(typeof(UltraWinGrid.UltraGridCell));
//get the cell that was clicked
if (cell != null)
//create a brand new event argument
Hashtable rowData = new Hashtable();
foreach (UltraWinGrid.UltraGridCell dataCell in row.Cells)
rowData.Add(dataCell.Column.Key, dataCell.Value);
}
OurRowEventArgs args = new OurRowEventArgs(row, row.Index, cell.Column.Key, cell.Value, cell.Text, rowData);
if (m_lastMouseButtonClicked == MouseButtons.Left)
OnRowClick(args);
else if (m_lastMouseButtonClicked == MouseButtons.Right)
ultraGrid1.ActiveRow = row;
OnRowRightClick(args);
...
this.OnClick(e);
The problem is that this does not work when I click on a merged cell. The row index is the one from the first cell in the merged group (even if I clicked on the third cell for example) so the active row gets set to the first one of the group, not the one I actually clicked on. So I tried to use the other method called "LastElementEntered".
Infragistics.Win.UIElement lastElement = ultraGrid1.DisplayLayout.UIElement.LastElementEntered;
bool rowNotSet = true;
// check if the cell is part of a merged set.
if (cell.GetMergedCells() != null)
cell = (UltraWinGrid.UltraGridCell)lastElement.GetContext(typeof(UltraWinGrid.UltraGridCell));
row = (UltraWinGrid.UltraGridRow)lastElement.GetContext(typeof(UltraWinGrid.UltraGridRow));
rowNotSet = false;
if (rowNotSet)
The problem is that the active row is not set all of the time. The first row I click on is set as the active one. Then if I click on another row, it is not set. I have to click a second time for the row to become active.
Have I missed something? Is there a better way to achieve what I am looking for?
Thanks for any input.Annie
P.S. We are using version 9.2.20091.2085
Hi Annie,
No, there's still no method on the grid, but getting the cell from a location is pretty easy:
HOWTO:UltraWinGrid Mouse Position and Cell Identification
I hit this problem with my project and was wondering if the suggested method "GetCellFromPoint" made it into one of the version of the grid.
Can you please let me know?Thanks.