Cómo configurar el fondo de la fila de DataGrid, basado en un valor de propiedad utilizando enlaces de datos

81

En mi código XAML, quiero establecer el Backgroundcolor de cada fila, según un valor del objeto en una fila específica. Tengo una ObservableCollectionde z, y cada zuna tiene una propiedad llamada State. Empecé con algo como esto en mi DataGrid:

<DataGrid.RowStyle>
    <Style TargetType="DataGridRow">
        <Setter Property="Background" 
                Value="{Binding z.StateId, Converter={StaticResource StateIdToColorConverter}}"/>
     </Style>
</DataGrid.RowStyle>

Este es un enfoque incorrecto porque x no es una propiedad en mi clase ViewModel.

En mi clase ViewModel tengo una ObservableCollection<z>que es la ItemsSourcede esto DataGridy una SelectedItemde tipo z.

Podría vincular el color a SelectedItem, pero esto solo cambiará una fila en el DataGrid.

¿Cómo puedo, en función de una propiedad, cambiar este color de fondo de filas?

Tobias Moe Thorstensen
fuente

Respuestas:

168

Utilice un DataTrigger:

<DataGrid ItemsSource="{Binding YourItemsSource}">
    <DataGrid.RowStyle>
        <Style TargetType="DataGridRow"> 
            <Style.Triggers>
                <DataTrigger Binding="{Binding State}" Value="State1">
                    <Setter Property="Background" Value="Red"></Setter>
                </DataTrigger>
                <DataTrigger Binding="{Binding State}" Value="State2">
                    <Setter Property="Background" Value="Green"></Setter>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </DataGrid.RowStyle>
</DataGrid>
Nitesh
fuente
2
Solo obtengo: Error de ruta BindingExpression: ¿Cómo 'State' property not found on 'object' ''z' (HashCode=7162954)'. BindingExpression:Path=State; DataItem='z' (HashCode=7162954); target element is 'DataGridRow' (Name=''); target property is 'NoTarget' (type 'Object')es posible que no encuentre el Estado de la propiedad cuando mi entidad tiene esto y mi base de datos muestra el Estado como una columna?
Tobias Moe Thorstensen
2
Espero que no lo estés haciendo como z.State.
Nitesh
4
Me encontré con esto nuevamente después de un tiempo libre de wpf, ¡desearía poder votar nuevamente!
Ric
5
Esto es genial. En la solución donde lo usé, necesitaba que el estado cambiara en función de un enumvalor. Esta respuesta en StackOverflow me ayudó con eso.
kaspermoerch
No olvide que la propiedad a la que se vincula tiene que serpublic
CAD bloke
17

Lo mismo se puede hacer sin DataTriggertambién:

 <DataGrid.RowStyle>
     <Style TargetType="DataGridRow">
         <Setter Property="Background" >
             <Setter.Value>
                 <Binding Path="State" Converter="{StaticResource BooleanToBrushConverter}">
                     <Binding.ConverterParameter>
                         <x:Array Type="SolidColorBrush">
                             <SolidColorBrush Color="{StaticResource RedColor}"/>
                             <SolidColorBrush Color="{StaticResource TransparentColor}"/>
                         </x:Array>
                     </Binding.ConverterParameter>
                 </Binding>
             </Setter.Value>
         </Setter>
     </Style>
 </DataGrid.RowStyle>

Dónde BooleanToBrushConverterestá la siguiente clase:

public class BooleanToBrushConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value == null)
            return Brushes.Transparent;

        Brush[] brushes = parameter as Brush[];
        if (brushes == null)
            return Brushes.Transparent;

        bool isTrue;
        bool.TryParse(value.ToString(), out isTrue);

        if (isTrue)
        {
            var brush =  (SolidColorBrush)brushes[0];
            return brush ?? Brushes.Transparent;
        }
        else
        {
            var brush = (SolidColorBrush)brushes[1];
            return brush ?? Brushes.Transparent;
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
Vahagn Nahapetyan
fuente
Aún mejor es la aplicación de un IMultiValueConverter ( docs.microsoft.com/en-us/dotnet/api/… ) para vincular simplemente más de una propiedad y hacer que el convertidor devuelva el color correcto para el estado de esas propiedades múltiples (omito la muestra, ya que es realmente similar a la caja del convertidor normal, pero puedo publicarla si alguien la necesita)
user8276908
7

En XAML, agregue y defina una propiedad RowStyle para DataGrid con el objetivo de establecer el fondo de la fila en el color definido en mi objeto de empleado.

<DataGrid AutoGenerateColumns="False" ItemsSource="EmployeeList">
   <DataGrid.RowStyle>
        <Style TargetType="DataGridRow">
             <Setter Property="Background" Value="{Binding ColorSet}"/>
        </Style>
   </DataGrid.RowStyle>

Y en mi clase de empleado

public class Employee {

    public int Id { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }

    public string ColorSet { get; set; }

    public Employee() { }

    public Employee(int id, string name, int age)
    {
        Id = id;
        Name = name;
        Age = age;
        if (Age > 50)
        {
            ColorSet = "Green";
        }
        else if (Age > 100)
        {
            ColorSet = "Red";
        }
        else
        {
            ColorSet = "White";
        }
    }
}

De esta manera, cada fila del DataGrid tiene el color de fondo de la ColorSet propiedad de mi objeto .

NICK_WANTED
fuente
Me gusta este método porque el color del objeto está centralizado en el modelo mismo en lugar de en la vista.
ΩmegaMan
1
Excepto que esto viola MVVM. Si no le importa, hágalo. Pero la experiencia del usuario no debe estar determinada por el modelo. Ese es el trabajo del modelo de vista / vista
BrianVPS