views:

181

answers:

2

When I tried to create a Style to DataGridTextColumn with the following code:

<Style TargetType="{x:Type DataGridTextColumn}">
           ...
</Style>

Visual Studio 2010 highlight {x:Type DataGridTextColumn} by blue line and said: Exception has been thrown by the target of an invocation.

A: 

Take a look at this link, its like a cheat sheet for styling datagrids:

http://blogs.msdn.com/jaimer/archive/2009/01/20/styling-microsoft-s-wpf-datagrid.aspx

DeanMc
Thank you, but there is nothing about styling DataGridColumn (only DataGridColumnHeaders)
Nike
Could you not style a cell and then bind that to a column? the same as you would for a listbox.
DeanMc
This link: http://www.codeproject.com/KB/WPF/WPFDataGridExamples.aspx#templates has more on styling actual columns using column templates, its about halfway down the page.
DeanMc
Actually I need to redefine DataGridTextColumn.EditingElementStyle for all Columns. I find only a example how to do it for explicitly difined Column in XAML here: http://msdn.microsoft.com/en-us/library/system.windows.controls.datagridboundcolumn.editingelementstyle(VS.95).aspx
Nike
+1  A: 

You can't style the DataGridTextColumn because DataGridTextColumn does not derive from FrameworkElement (or FrameworkContentElement). Only FrameworkElement, etc supports styling.

When you attempt to create a style in XAML for any type that is not a FrameworkElement or FrameworkContentElement you get that error message.

How do you solve this? As with any problem, where there is a will there is a way. In this case I think the easiest solution is to create an attached property for DataGrid to assign a DataGridColumn style:

<DataGrid ...>
  <local:MyDataGridHelper.TextColumnStyle>
    <Style TargetType="FrameworkElement">
      ... setters here ...
    </Style>
  </local:MyDataGridHelper.TextColumnStyle>
  ...

The implementation would be something along these lines:

public class MyDataGridHelper : DependencyObject
{
  // Use propa snipped to create attached TextColumnStyle with metadata:
  ... RegisterAttached("TextColumnStyle", typeof(Style), typeof(MyDataGridHelper), new PropertyMetadata
  {
    PropertyChangedCallback = (obj, e) =>
    {
      var grid = (DataGrid)obj;
      if(e.OldValue==null && e.NewValue!=null)
        grid.Columns.CollectionChanged += (obj2, e2) =>
        {
          UpdateColumnStyles(grid);
        }
    }
  }
  private void UpdateStyles(DataGrid grid)
  {
    var style = GetTextColumnStyle(grid);
    foreach(var column in grid.Columns.OfType<DataGridTextColumn>())
      foreach(var setter in style.Setters.OfType<Setter>())
        if(setter.Value is BindingBase)
          BindingOperations.SetBinding(column, setter.Property, setter.Value);
        else
          column.SetValue(setter.Property, setter.Value);
  }
}

The way this works is, any time the attached property is changed, a handler is added for the Columns.CollectionChanged event on the grid. When the CollectionChanged event fires, all columns are updated with the style that was set.

Note that the above code does not handle the situation where a style is removed and re-added gracefully: Two event handlers are registered. For a really robust solution you would want to fix this by adding another attached property containing the event handler so the event handler could be unregistered, but for your purpose I think this is unimportant.

Another caveat here is that the direct use of SetBinding and SetValue will cause the DependencyProperty to have a BaseValueSource of Local instead of DefaultStyle. This will probably make no difference in your case but I thought I should mention it.

Ray Burns