WPF Datagrid alinea columnas numéricas
wpfdatagrid (2)
Una forma de hacerlo es configurar los desencadenadores en código subyacente. El siguiente método aplica un activador a DataGridColumn. Este desencadenador usa su IsNumericConverter
para determinar si se realiza la alineación a la derecha:
public static void AddTriggerToColumnStyle(DataGridColumn column)
{
var boundColumn = column as DataGridBoundColumn;
if (boundColumn != null && boundColumn.Binding is Binding)
{
string bindingPropertyPath = (boundColumn.Binding as Binding).Path.Path;
column.CellStyle = new Style()
{
BasedOn = column.CellStyle,
TargetType = typeof(DataGridCell),
Triggers =
{
new DataTrigger
{
Binding = new Binding(bindingPropertyPath) { Converter = new IsNumericConverter() },
Value = true,
Setters =
{
new Setter
{
Property = TextBlock.TextAlignmentProperty,
Value = TextAlignment.Right
}
}
}
}
};
}
}
Este método debe ser seguro para llamar a InitializeComponent()
en el constructor de código subyacente.
Este enfoque funcionará si la columna tiene una mezcla de datos numéricos y no numéricos. Si las columnas contienen solo datos de un tipo, este enfoque seguirá funcionando, pero los activadores creados nunca se dispararán o permanecerán disparados permanentemente.
Por supuesto, el método anterior no tiene que repetirse en el código subyacente para cada control que use DataGrids. Puede moverlo a una clase de utilidad estática y hacer que todas las clases de código subyacente invoquen este método. Incluso podría agregar un método de utilidad estático que recorre las columnas en un DataGrid que lo pasa y llama al método anterior para cada columna.
ACTUALIZACIÓN : modifiqué el método anterior para permitirle deducir la ruta de propiedad de enlace. Eso hace que sea más fácil de usar. También hice public
y static
el método para que quede claro que se puede mover a una clase de utilidad estática.
Pensé en otro enfoque, que se ejecutaría a través de todas las columnas en un DataGrid, inspeccionar los enlaces, deducir el tipo de propiedad vinculada y aplicar la alineación a la derecha a la columna. Esto evitaría la creación de desencadenantes que nunca disparen o permanezcan disparados permanentemente, y quizás se ajusten al caso en el que cada columna contiene datos de un tipo solo un poco mejor. Sin embargo, este enfoque seguiría implicando código subyacente, necesitaría pasar el tipo al que estaría asociada cada fila, y se complicaría si las rutas de propiedad de enlace implicaran algo más que un solo nombre de propiedad.
Me temo que no puedo ver una solución a este problema que solo use Style
s y evite el código subyacente.
Intento crear un estilo para las celdas de DataGrid en mi aplicación. Supongo que tal vez haya una manera de alinear correctamente las celdas numéricas en DataGrid usando un DataTrigger. ¿Esto es posible?
Mi estilo para mi DataGrid es este:
<Style TargetType="{x:Type DataGrid}">
<Setter Property="AlternatingRowBackground">
<Setter.Value>
<SolidColorBrush Color="#CCCCCC" />
</Setter.Value>
</Setter>
<Setter Property="CanUserAddRows" Value="False" />
<Setter Property="CanUserDeleteRows" Value="False" />
<Setter Property="Background">
<Setter.Value>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<GradientStop Offset="0" Color="#CCCCCC" />
<GradientStop Offset="1" Color="#FFFFFF" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
<Setter Property="RowHeaderWidth" Value="0" />
<Setter Property="CellStyle">
<Setter.Value>
<Style TargetType="{x:Type DataGridCell}">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background">
<Setter.Value>
<SolidColorBrush Color="#7777FF" />
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</Setter.Value>
</Setter>
</Style>
Estoy pensando en agregar algún tipo de disparador en el CellStyle para detectar si el contenido es numérico (int, doble, decimal, ...) y darle un estilo a la celda en consecuencia. es posible?
Actualizar
Pensando en esto, probé varias cosas, pero no funcionó. Intenté usar un DataTrigger definido como:
<DataTrigger Binding="{Binding Converter={StaticResource IsNumericConverter}}" Value="True">
<Setter Property="HorizontalContentAlignment" Value="Right" />
</DataTrigger>
Donde IsNumericConverter
es:
public class IsNumericConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value is int || (value is decimal || value is double);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
}
Pero cuando establezco un punto de interrupción en el convertidor, entiendo que el valor es del tipo de toda la fila, no de cada celda individual ...
Sé que esto tiene tres años, pero pude hacer esto sin agregar ningún código al código subyacente y pensé que compartiría cómo. usando este artículo como modelo: enlace
Utiliza multibinding como una forma de resolver su problema original de pasar una fila a su convertidor.
agregue esto a su cuadrícula de datos:
CellStyle="{StaticResource CellRightAlignStyle }"
luego agrega este estilo a tu xaml, debes agregarlo como recurso:
<Window.Resources>
<Style x:Key="CellRightAlignStyle" TargetType="{x:Type DataGridCell}">
<Setter Property="HorizontalAlignment">
<Setter.Value>
<MultiBinding
Converter="{converters:IsNumericConverter}" >
<MultiBinding.Bindings>
<Binding RelativeSource="{RelativeSource Self}"/>
<Binding Path="Row" Mode="OneWay"/>
</MultiBinding.Bindings>
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
Entonces el convertidor:
public object Convert(
object[] values,
Type targetType,
object parameter,
CultureInfo culture)
{
if (values[1] is DataRow)
{
//change the text alignment left or right.
var cell = (DataGridCell)values[0];
var row = (DataRow)values[1];
var columnName = cell.Column.SortMemberPath;
if (row[columnName] is int || (row[columnName] is decimal || row[columnName] is double))
return System.Windows.HorizontalAlignment.Right;
}
return System.Windows.HorizontalAlignment.Left;
}
public override object ConvertBack(
object value,
Type targetType,
object parameter,
CultureInfo culture)
{
return null;
}
¡eso es todo ahora, las celdas que contienen datos numéricos deben alinearse a la derecha!