¿Por qué no puedo diseñar un DataGridTextColumn?

Traté de crear un estilo para DataGridTextColumn con el siguiente código

  ...  

Sin embargo, Visual Studio 2010 resalta {x:Type DataGridTextColumn} con una línea azul y elabora: Exception has been thrown by the target of an invocation.

¿Por qué sucede esto y cómo lo soluciono?

No se puede DataGridTextColumn estilo a DataGridTextColumn porque DataGridTextColumn no se deriva de FrameworkElement (o FrameworkContentElement ). Solo FrameworkElement, etc. es compatible con el estilo.

Cuando intentas crear un estilo en XAML para cualquier tipo que no sea FrameworkElement o FrameworkContentElement , obtienes ese mensaje de error.

¿Cómo resuelves esto? Como con cualquier problema, donde hay voluntad, hay una manera. En este caso, creo que la solución más fácil es crear una propiedad adjunta para que DataGrid asigne un estilo DataGridColumn:

     ... 

La implementación sería algo así:

 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); } } 

La forma en que esto funciona es que cada vez que se cambia la propiedad adjunta, se agrega un controlador para el evento Columns.CollectionChanged en la cuadrícula. Cuando se desencadena el evento CollectionChanged, todas las columnas se actualizan con el estilo establecido.

Tenga en cuenta que el código anterior no maneja la situación en la que un estilo se elimina y se vuelve a agregar correctamente: se registran dos controladores de eventos. Para una solución realmente robusta, querría arreglar esto agregando otra propiedad adjunta que contenga el controlador de eventos para que el controlador de eventos no pueda ser registrado, pero para su propósito, creo que esto no es importante.

Otra advertencia aquí es que el uso directo de SetBinding y SetValue hará que DependencyProperty tenga un BaseValueSource de Local lugar de DefaultStyle . Esto probablemente no hará ninguna diferencia en su caso, pero pensé que debería mencionarlo.

La etiqueta de estilo debe ir en el lugar correcto. Su cuadrícula de datos puede parecerse a esto ahora mismo:

       

Inicialmente, puede intentar agregar la etiqueta de estilo directamente dentro del elemento DataGridTextColumn, que no funcionará. Sin embargo, puede crear elementos para “DataGridTextColumn.ElementStyle” y / o “DataGridTextColumn.EditingElementStyle” solo dentro del elemento “DataGridTextColumn”. Cada una de esas tags de elemento puede tener tags de estilo dentro de ellas:

              

Se aplicará un estilo para ver y el otro se aplicará cuando la celda esté en modo de edición. Tenga en cuenta que cambia de un TextBlock al visualizar en un TextBox al editar (¡Esto me dio al principio!).

Echa un vistazo a este enlace, es como una hoja de trucos para diseñar grillas de datos:

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

Esto es más una adición a la respuesta de Ray Burns. La primera vez no pude implementarlo por mi cuenta, pero con la ayuda de mm8 ( https://stackoverflow.com/a/46690951/5381620 ) lo ejecuté. Funciona realmente bien. Para otras personas que tienen problemas para seguir este enfoque de propiedad adjunta, tal vez sea útil un fragmento de código completo.

 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

            

Editar : En primer enfoque, sobrescribí todo el estilo. En la nueva versión todavía es posible mantener otras modificaciones de estilos como esta

    

Más simple:

 Snap ITC   

Un DataGridTextColumn no es más que una columna con un TextBlock en él. Escriba un estilo con TargetType como TextBlock y vincule la propiedad ElementStyle de DataGridTextColumn con este. ¡Espero que ayude!