Matheew
Matheew

Reputation: 355

Avalonia UI C# XAML WPF - Adjust data grid row color based on column value

public class EventLogView : UserControl
{
    private DataGrid dataGrid;
    public EventLogView()
    {
        this.InitializeComponent();
        dataGrid = this.FindControl<DataGrid>("EventLogsDataGrid");
        this.dataGrid.LoadingRow += new EventHandler<DataGridRowEventArgs>(dataGrid_LoadingRows);
    } 

    private void InitializeComponent()
    {
        AvaloniaXamlLoader.Load(this);
    }

    void dataGrid_LoadingRows(object sender, DataGridRowEventArgs e)
    {

    }
}

I would like to change every row color to the red, if the 4th column's value is "HIGH".

Upvotes: 1

Views: 5089

Answers (3)

Maksim Rozhkov
Maksim Rozhkov

Reputation: 11

There may be another way to do the same thing, but in XAML. To be honest, I don’t compete the quest, but it was really close. The author of Avalonia.Xaml.Behaviors Wiesław Šoltés has posted an example of a very interesting approach. I tried to adopt it for use with the DataGrid’s row and it almost worked:

<Window xmlns="https://github.com/avaloniaui"
        xmlns:int="clr-namespace:Avalonia.Xaml.Interactivity;assembly=Avalonia.Xaml.Interactivity"
        xmlns:ia="clr-namespace:Avalonia.Xaml.Interactions.Core;assembly=Avalonia.Xaml.Interactions"        
        x:Class="BvsDesktopLinux.Views.MainWindow" ...>
...
<Window.Styles>
    <Style Selector="DataGridCell.statusColumn">
        <Setter Property="FontSize" Value="24"/>
        <Setter Property="(int:Interaction.Behaviors)">
            <int:BehaviorCollectionTemplate>
                <int:BehaviorCollection>
                    <ia:DataTriggerBehavior Binding="{Binding Status}" ComparisonCondition="Equal" Value="Rejected">
                        <ia:ChangePropertyAction TargetObject="DataGridCell" PropertyName="Background" Value="Red" />
                    </ia:DataTriggerBehavior>
                </int:BehaviorCollection>
            </int:BehaviorCollectionTemplate>
        </Setter>
    </Style>
</Window.Styles>
...
<DataGrid AutoGenerateColumns="False" Margin="10"
          Items="{Binding Banknotes}" SelectedItem="{Binding SelectedBanknote}">
    <DataGrid.Columns>
        <DataGridTextColumn Header="{x:Static p:Resources.NoteId}" Binding="{Binding Id}" />
        <DataGridTextColumn Header="{x:Static p:Resources.NoteCurrency}" Binding="{Binding Currency}" />
        <DataGridTextColumn Header="{x:Static p:Resources.NoteDenomination}" Binding="{Binding Denomination}" />
        <DataGridTextColumn Header="{x:Static p:Resources.Status}" Binding="{Binding Status}" CellStyleClasses="statusColumn" />
    </DataGrid.Columns>
</DataGrid>

I only had one problem with the code – the binding doesn't use the DataGridCell's DataContext (the element of the ObservableCollection from the ViewModel), but it uses the DataContext of the whole View/Window (ViewModel).

Upvotes: 1

Maksim Rozhkov
Maksim Rozhkov

Reputation: 11

@mm8: Thanks for the useful hint! I was looking for the same answer and started with your advice. I ran into a problem after sorting the rows, or reloading the content with some modifications. Several rows that didn't match the criteria had the background property attached. So I used styles to attach/detach the style:

<Window.Styles>
    <Style Selector="DataGridRow.rejectedStatus">
        <Setter Property="Background" Value="Red"/>
        <Setter Property="Foreground" Value="White"/>
    </Style>
</Window.Styles>
private void DataGrid_OnLoadingRow(object? sender, DataGridRowEventArgs e)
{
    var dataObject = e.Row.DataContext as Models.Banknote;
    if (dataObject != null && dataObject.Status == "Rejected")
    {
        e.Row.Classes.Add("rejectedStatus");
    }
    else
    {
        e.Row.Classes.Remove("rejectedStatus");
    }
}

Upvotes: 0

mm8
mm8

Reputation: 169330

The way to do this in "pure" WPF would be to define an ItemContainerStyle with a DataTrigger:

<DataGrid x:Name="EventLogsDataGrid"
                  AutoGenerateColumns="False"
                  Items="{Binding LogsData}"
                  CanUserReorderColumns="True"
                  CanUserResizeColumns="True"
                  IsReadOnly="True">
    <DataGrid.ItemContainerStyle>
        <Style TargetType="DataGridRow">
            <Style.Triggers>
                <DataTrigger Binding="{Binding Importance}" Value="HIGH">
                    <Setter Property="Background" Value="Red" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </DataGrid.ItemContainerStyle>
    <DataGrid.Columns>
        <DataGridTextColumn Binding="{Binding Id}"
                                Header="ID"
                                Width="Auto"/>
        <DataGridTextColumn Binding="{Binding Content}"
                                Header="Content"
                                Width="Auto"/>
        <DataGridTextColumn Binding="{Binding CreationDate}"
                                Header="Date Time"
                                Width="Auto"/>
        <DataGridTextColumn Binding="{Binding Source}"
                                Header="Source"
                                Width="Auto"/>
        <DataGridTextColumn Binding="{Binding Importance}"
                                Header="Priority"
                                Width="Auto"/>
    </DataGrid.Columns>
</DataGrid>

But since Avalonia doesn't support triggers, you may have to handle the LoadingRow event something like this to set the Background property programmtically:

void dataGrid_LoadingRows(object sender, DataGridRowEventArgs e)
{
    var dataObject = e.Row.DataContext as YourDataObject;
    if (dataObject != null && dataObject.Importance == "HIGH")
        e.Row.Background = Brushes.Red;
}

Upvotes: 1

Related Questions