Select to view content in your preferred language

Change VisualState of Graphic from Code-Behind

903
3
08-24-2012 09:44 AM
DavidMarley
Frequent Contributor
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; 
} 
0 Kudos
3 Replies
DominiqueBroux
Esri Frequent Contributor
AFAIK there is no way to do that.
The problem being to get the underlying UI element under a graphic. But maybe someone found out a hack!
0 Kudos
DavidMarley
Frequent Contributor
Thanks Dominique - I think you are right...the challenge is getting a reference to the underlying UI element, if even possible. 

For the moment I just bailed on the highlight/rollover behavior.  Plus I have other ways I could do it - for example with a separate graphics layer and graphics specifically for highlighting...though that has its own wrinkles and adds some extra complexity.  I was hoping for a cleaner solution just by manipuating visual states but I at the moment that's not looking like a workable solution.

Dave
0 Kudos
teamIgal
Deactivated User
Hello,

Sorry for bringing up an ols thread - but i came across the same problem.

i have polygons in a feature layer - and i want to change their color to be blinking when i change some property from code behind.
i am using custom FillMarker with storboard that can make the blinking.

i was thinking about using visualStateGroup of my own - and to change the graphic StateGroup from the code behind - but i can't find a way to change that.

Do you have any suggestion?


the only thing i came up with so far - which is not a very pretty workaround - is to change the graphic symbol to be the blinking symbol - and set a timer for a few seconds, and then change the symbol back.

Thanks in advance,
Team Igal
0 Kudos