Friday, December 26, 2008

A Solution to DataGrid with Tooltips Shortcomings

DataGrid with a Custom RowDetailsTemplate
Silverlight RTM has a DataGrid control. To learn more about basic usage, please refer to http://blogs.msdn.com/scmorris/archive/2008/03/21/using-the-silverlight-datagrid.aspx

Beyond the basics, DataGrid has a few shortcomings. Let's say we have a static DataGrid declaration that looks like this:







































Where the ItemsSource of the DataGrid is defined by a List collection:


public class GridData
{
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
public bool Available { get; set; }
}


DataContext of Grid not associated with ToolTip's DataContext by default
The first annoyance is ToolTip does not inherit the DataContext (entry in the List) associated with the Row that contains it. Compiling the above code will result in the Record # binding picking up the correct Binding while the custom ToolTip.Content will not.



The Solution is to add a handler for a Loaded Event to the Grid that begins our DataTemplate definition:
 
<grid loaded="Grid_DataContext_Fixer">
<tooltipservice.tooltip>
<tooltip></tooltip>
</tooltipservice.tooltip>
</grid>

Inside the handler, we use the ToolTipService to manually set Grid's DataContext to the DataContext of the Tooltip like so:

private void Grid_DataContext_Fixer(object sender, RoutedEventArgs e)
{
ToolTip t = ToolTipService.GetToolTip(sender as Grid) as ToolTip;
t.DataContext = (sender as Grid).DataContext;
}


The ToolTip will now properly understand the binding.



Sorting DataGrid will break ToolTip associations
When user sorts the DataGrid ToolTips are not re-ordered along with the view.



Why this happens is not clear. ToolTipService does bind to the right Object reference yet the DataContext remains tied to the ordering of items in the original List.

A Solution. This time we add a MouseEnter event handler to the same Grid.


<grid loaded="Grid_DataContext_Fixer" mouseenter="Grid_DataContext_Fixer">
<tooltipservice.tooltip>
<tooltip>...</tooltip>
</tooltipservice.tooltip>
</grid>


In fact, the MouseEnter event will do exactly the same thing as before. Namely, the Grid's context will be reassigned to the Tooltip. As shown above, we handle both events with the same handler.

We now get expected behavior.



If you have a better solution, please do provide feedback in the Comments.

1 comment:

  1. By far the most elegant solution I have seen for the datacontext issue, keep up the good work.

    ReplyDelete