Por que não posso estilizar um DataGridTextColumn?

Eu tentei criar um estilo para DataGridTextColumn com o seguinte código

  ...  

No entanto, o Visual Studio 2010 destaca {x:Type DataGridTextColumn} com uma linha azul e elabora: A Exception has been thrown by the target of an invocation.

Por que isso acontece e como faço para corrigir isso?

Você não pode estilizar o DataGridTextColumn porque DataGridTextColumn não deriva de FrameworkElement (ou FrameworkContentElement ). Apenas FrameworkElement, etc suporta estilo.

Quando você tenta criar um estilo em XAML para qualquer tipo que não seja um FrameworkElement ou FrameworkContentElement você recebe essa mensagem de erro.

Como voce resolve isso? Como acontece com qualquer problema, onde há vontade há um caminho. Nesse caso, acho que a solução mais fácil é criar uma propriedade anexada para o DataGrid designar um estilo DataGridColumn:

     ... 

A implementação seria algo ao longo destas linhas:

 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()) foreach(var setter in style.Setters.OfType()) if(setter.Value is BindingBase) BindingOperations.SetBinding(column, setter.Property, setter.Value); else column.SetValue(setter.Property, setter.Value); } } 

A maneira como isso funciona é, sempre que a propriedade anexada é alterada, um manipulador é adicionado para o evento Columns.CollectionChanged na grade. Quando o evento CollectionChanged é triggersdo, todas as colunas são atualizadas com o estilo que foi definido.

Observe que o código acima não controla a situação em que um estilo é removido e incluído novamente com elegância: Dois manipuladores de events são registrados. Para uma solução realmente robusta, você desejaria corrigir isso adicionando outra propriedade anexada contendo o manipulador de events, para que o manipulador de events pudesse ser cancelado, mas para seu propósito, acho que isso não é importante.

Outra advertência aqui é que o uso direto de SetBinding e SetValue fará com que o DependencyProperty tenha um BaseValueSource de Local vez de DefaultStyle . Isso provavelmente não fará diferença no seu caso, mas eu pensei que deveria mencioná-lo.

A tag de estilo tem que ir no lugar certo. Seu datagrid pode ser algo parecido com isso agora:

       

Você pode inicialmente tentar adicionar a tag de estilo diretamente no elemento DataGridTextColumn, o que não funcionará. Você pode, no entanto, criar elementos para “DataGridTextColumn.ElementStyle” e ou “DataGridTextColumn.EditingElementStyle” apenas dentro do elemento “DataGridTextColumn”. Cada uma dessas tags de elemento pode ter tags de estilo dentro delas:

              

Um estilo será aplicado à visualização e o outro será aplicado quando a célula estiver no modo de edição. Observe que ele muda de um TextBlock ao visualizar um TextBox ao editar (Isso me pegou primeiro!).

Dê uma olhada neste link, é como uma folha de dicas para estilizar datagrids:

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

Isso é mais uma adição à resposta do Ray Burns. Primeiro não fui capaz de implementá-lo por conta própria, mas com a ajuda de mm8 ( https://stackoverflow.com/a/46690951/5381620 ) eu comecei a correr. Funciona muito bem. Para outras pessoas que têm problemas com essa abordagem de propriedade anexada, talvez um trecho de código completo seja útil.

 public class MyDataGridHelper : DependencyObject { private static readonly DependencyProperty TextColumnStyleProperty = DependencyProperty.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); }; } }); public static void SetTextColumnStyle(DependencyObject element, Style value) { element.SetValue(TextColumnStyleProperty, value); } public static Style GetTextColumnStyle(DependencyObject element) { return (Style)element.GetValue(TextColumnStyleProperty); } private static void UpdateColumnStyles(DataGrid grid) { var origStyle = GetTextColumnStyle(grid); foreach (var column in grid.Columns.OfType()) { //may not add setters to a style which is already in use //therefore we need to create a new style merging //original style with setters from attached property var newStyle = new Style(); newStyle.BasedOn = column.ElementStyle; newStyle.TargetType = origStyle.TargetType; foreach (var setter in origStyle.Setters.OfType()) { newStyle.Setters.Add(setter); } column.ElementStyle = newStyle; } } } 

xaml

            

Edit : Na primeira abordagem eu sobrescrevi todo o estilo. Na nova versão ainda é possível manter outras modificações de estilos como esta

    

Mais simples:

 Snap ITC   

Um DataGridTextColumn não é nada além de uma coluna com um TextBlock. Escreva um estilo com o TargetType como TextBlock e vincule a propriedade ElementStyle do DataGridTextColumn a ele. Espero que ajude!