I am trying to work out independent roll-over and click behavior between rows in a DataGrid and graphics on a GraphicsLayer, where GraphicsLayer and DataGrid have same data source. The Spatial Query sample comes close, however it selects on mouseover rather than just highlighting. I don't want to do this because I want to select only on a click, and want to maintain that selction regardless of what features are rolled over with the mouse.So the behavior I want is (the hard part is the highlighting - the selection is actually pretty easy):
- Clicking on a graphic SELECTS the corresponding row in datagrid.
- Clicking on a row in datagrid SELECTS the corresponding graphic.
- Mouseover a graphic highlights (but does not select) the corresponding row in datagrid.
- Mouseover a row in datagrid highlights (but does not select) the corresponding graphic.
I almost have this working - I am able to change the visual state of the DataGrid when rolling over a graphic, using VisualStateManager. However I cannot do the same to change graphic's visual state on DataGrid row rollover, because VisualStateManager.GoToState requires a Control as input and Graphic inherits from DependencyObject. So is there some other way to set the graphic's visual state?Here are the MouseEnter/Leave events for the Graphic, to set the DataGridRow - these work:private void graphicsLayer_MouseLeave(object sender, GraphicMouseEventArgs e)
{
DataGridRow row = getDataGridRowByDataContext(dgGeofences, e.Graphic);
if (dgGeofences.SelectedItem == e.Graphic)
VisualStateManager.GoToState(row, "Normal Selected", true);
else
VisualStateManager.GoToState(row, "Normal", true);
}
private void graphicsLayer_MouseEnter(object sender, GraphicMouseEventArgs e)
{
// Highlight on rollover
DataGridRow row = getDataGridRowByDataContext(dgGeofences, e.Graphic);
VisualStateManager.GoToState(row, "MouseOver", true);
}
Here is what I want to do for the MouseEnter/Leave events for the DataGridRow - but cannot pass graphic to VisualStateManager:private void Row_MouseLeave(object sender, MouseEventArgs e)
{
DataGridRow row = sender as DataGridRow;
Graphic graphic = row.DataContext as Graphic;
VisualStateManager.GoToState(graphic, "Normal", true); // Compile Error - graphic is not a Control
}
private void Row_MouseEnter(object sender, MouseEventArgs e)
{
DataGridRow row = sender as DataGridRow;
Graphic graphic = row.DataContext as Graphic;
VisualStateManager.GoToState(graphic, "MouseOver", true); // Compile Error - graphic is not a Control
}
For the sake of completeness, here is the method I use to get the DataGridRow corresponding to a graphic (this turned out to be tricky in and of itself, but I found this approach online):private DataGridRow getDataGridRowByDataContext(DataGrid dataGrid, object dataContext) {
if (null != dataContext)
{
dataGrid.ScrollIntoView(dataContext, null);
DataGridAutomationPeer automationPeer = (DataGridAutomationPeer)DataGridAutomationPeer.CreatePeerForElement(dataGrid);
// Get the DataGridRowsPresenterAutomationPeer so we can find the rows in the data grid...
DataGridRowsPresenterAutomationPeer dataGridRowsPresenterAutomationPeer = automationPeer.GetChildren().Where(a => (a is DataGridRowsPresenterAutomationPeer)).Select(a => (a as DataGridRowsPresenterAutomationPeer)).FirstOrDefault();
if (null != dataGridRowsPresenterAutomationPeer)
{
foreach (var item in dataGridRowsPresenterAutomationPeer.GetChildren())
{
// loop to find the DataGridCellAutomationPeer from which we can interrogate the owner -- which is a DataGridRow
foreach (var subitem in (item as DataGridItemAutomationPeer).GetChildren())
{
if ((subitem is DataGridCellAutomationPeer))
{
// At last -- the only public method for finding a row....
DataGridRow row = DataGridRow.GetRowContainingElement(((subitem as DataGridCellAutomationPeer).Owner as FrameworkElement));
// check this row to see if it is bound to the requested dataContext.
if ((row.DataContext) == dataContext)
{
return row;
}
break; // Only need to check one cell in each row
}
}
}
}
}
return null;
}