Jak ustawić tło wiersza DataGrid na podstawie wartości właściwości przy użyciu powiązań danych

81

W moim kodzie XAML chcę ustawić Backgroundkolor każdego wiersza na podstawie wartości obiektu w jednym określonym wierszu. Mam ObservableCollectionof z, a każdy z nich zma właściwość o nazwie State. Zacząłem od czegoś takiego w moim DataGrid:

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

Jest to niewłaściwe podejście, ponieważ x nie jest właściwością w mojej klasie ViewModel.

W mojej klasie ViewModel mam ObservableCollection<z>który jest ItemsSourcetego DataGridi SelectedItemtyp z.

Mógłbym związać kolor SelectedItem , ale to zmieni tylko jeden wiersz w DataGrid.

Jak mogę, w oparciu o jedną właściwość, zmienić te wiersze backgroundcolor?

Tobias Moe Thorstensen
źródło

Odpowiedzi:

171

Użyj 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
źródło
2
Dostaję tylko: Błąd ścieżki BindingExpression: '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')Dlaczego nie znajduje stanu właściwości, gdy moja jednostka to przechowuje, a moja baza danych pokazuje stan jako kolumnę?
Tobias Moe Thorstensen,
2
Mam nadzieję, że nie robisz tego jako z.State.
Nitesh,
4
Właśnie natknąłem się na to ponownie po przerwie w wpf, chciałbym móc ponownie zagłosować!
Ric,
5
To jest świetne. W rozwiązaniu, w którym go użyłem, potrzebowałem zmiany stanu na podstawie enumwartości. Ta odpowiedź na StackOverflow pomogła mi w tym.
kaspermoerch
Nie zapomnij, że nieruchomość, z którą się łączysz, musi byćpublic
facet z CAD
17

To samo można zrobić bez DataTrigger:

 <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>

Gdzie BooleanToBrushConverterjest następująca klasa:

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
źródło
Jeszcze lepsze jest zastosowanie IMultiValueConverter ( docs.microsoft.com/en-us/dotnet/api/… ), aby po prostu powiązać więcej niż jedną właściwość i poprosić konwerter o zwrócenie prawidłowego koloru dla stanu tych wielu właściwości (pomijam próbka, ponieważ jest bardzo podobna do zwykłej obudowy konwertera, ale mogę ją opublikować, jeśli ktoś jej potrzebuje)
user8276908
7

W języku XAML dodaj i zdefiniuj właściwość RowStyle dla DataGrid, aby ustawić tło wiersza na kolor zdefiniowany w moim obiekcie pracownika.

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

I w mojej klasie pracowniczej

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

W ten sposób każdy wiersz DataGrid ma kolor tła z ColorSet Własności mojego obiektu .

NICK_WANTED
źródło
Podoba mi się ta metoda, ponieważ kolor obiektu jest scentralizowany w samym modelu zamiast w widoku.
ΩmegaMan
1
Tyle że to narusza MVVM. Jeśli cię to nie obchodzi, zrób to. Ale doświadczenie użytkownika nie powinno być determinowane przez model. To zadanie View / View Model
BrianVPS,