Home > Enterprise >  WPF MVVM How change bg color of DataGridRow on change event from group of radiobuttons?
WPF MVVM How change bg color of DataGridRow on change event from group of radiobuttons?

Time:12-01

I have DataGrid with column names "Source" and "Change source" with 3 radio buttons in it.

Exampl

I'm trying to fill the background of a row when changing the value of a radio button if the values in the columns are not equal. i.e. I need to track changes, if the source has changed, then highlight the line, if the source returned to the value indicated in the "Source" column, then remove the highlight.

How do I achieve this, please help

XAML

<DataGrid.RowStyle>
    <Style TargetType="DataGridRow">        
        <Style.Triggers>
            <DataTrigger Binding="{Binding StateRowChanged}" Value="True">
                <Setter Property="Background" Value="Red"></Setter>
            </DataTrigger>
            <DataTrigger Binding="{Binding StateRowChanged}" Value="False">
                <Setter Property="Background" Value="White"></Setter>
            </DataTrigger>             
        </Style.Triggers>
    </Style>
</DataGrid.RowStyle>

........

<DataGridTextColumn Header="Source" Binding="{Binding Path='Source'}" IsReadOnly="True" />
<DataGridTemplateColumn Header="Change source" >
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal" >
                <RadioButton Cursor="Hand" Padding="5 0" Content="c" GroupName="{Binding id}"   
                    IsChecked="{Binding selectedSrcOption,UpdateSourceTrigger=PropertyChanged,
                    Converter={StaticResource RadioButtonCheckedConverter}, 
                    ConverterParameter={x:Static local:SrcOptions.C}}"/>
                 <RadioButton Cursor="Hand" Padding="5 0" Content="i" GroupName="{Binding id}"   
                        IsChecked="{Binding selectedSrcOption,UpdateSourceTrigger=PropertyChanged,
                        Converter={StaticResource RadioButtonCheckedConverter}, 
                        ConverterParameter={x:Static local:SrcOptions.I}}"/>
                <RadioButton  Cursor="Hand" Padding="5 0" Content="m" GroupName="{Binding id}" 
                        IsChecked="{Binding selectedSrcOption,UpdateSourceTrigger=PropertyChanged,
                        Converter={StaticResource RadioButtonCheckedConverter}, 
                        ConverterParameter={x:Static local:SrcOptions.M}}"/>
            </StackPanel>
         </DataTemplate>
</DataGridTemplateColumn.CellTemplate>

Model

...some props...

private bool _stateRowChanged;
public bool StateRowChanged
{
    get{return _stateRowChanged;}
    set{
        if (value == _stateRowChanged) return;
        _stateRowChanged = value;
        OnPropertyChanged("StateRowChanged");
        }
}

MainWindowViewModel


new MyModel { id=0,Source="c",selectedSrcOption="c"};
new MyModel { id=1,Source="i",selectedSrcOption="m"}; 
new MyModel { id=2,Source="m",selectedSrcOption="c"};

..

foreach (MyModel m in Data.AllItems)
{
    m.PropertyChanged  = EntryOnPropertyChanged;
}
...

private void EntryOnPropertyChanged(object sender, PropertyChangedEventArgs args)
{
    if (args.PropertyName == nameof(MyModel.selectedSrcOption))
    {
    //Gets radio button click event!
    MessageBox.Show(args.PropertyName.ToString());
    //How to check if Source != selectedSrcOption 
    //and change StateRowChanged prop?

    }
}

CodePudding user response:

It is necessary to add a style in which there is a trigger that sets the background color of the row for different values of properties.
Also, if there is a limited constant list of valid values, then I would advise you to implement it as an Enum.
And to implement a list of buttons, it's better to use a ListBox.

using System;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Windows.Data;

namespace Core2022.SO.John.ChangeSource
{
    public enum SourceEnum
    {
        c, i, m
    }

    public class SourceModel
    {
        public int Id { get; set; }
        public SourceEnum Source { get; set; }

        public SourceEnum SelectedSource { get; set; }
    }
    public class SourcesViewModel
    {
        public static ReadOnlyCollection<SourceEnum> Sources { get; } = Array.AsReadOnly(Enum.GetValues<SourceEnum>());
        public SourceModel[] SourceModels { get; } =
        {
            new SourceModel { Id=0, Source=SourceEnum.c, SelectedSource=SourceEnum.c},
            new SourceModel { Id=1, Source=SourceEnum.i, SelectedSource=SourceEnum.m},
            new SourceModel { Id=2, Source=SourceEnum.m, SelectedSource=SourceEnum.c}
        };
    }
    public class EqualsConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            return Equals(values[0], values[1]);
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        private EqualsConverter() { }
        public static EqualsConverter Insatance { get; } = new();
    }
}
<Window x:Class="Core2022.SO.John.ChangeSource.SourcesWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Core2022.SO.John.ChangeSource"
        mc:Ignorable="d"
        Title="SourcesWindow" Height="450" Width="800"
        DataContext="{DynamicResource vm}">
    <Window.Resources>
        <local:SourcesViewModel x:Key="vm"/>
        <DataTemplate x:Key="SelectedSource.Template"
                      DataType="local:SourceModel">
            <ListBox ItemsSource="{x:Static local:SourcesViewModel.Sources}"
                     SelectedItem="{Binding SelectedSource, UpdateSourceTrigger=PropertyChanged}"
                     Background="Transparent">
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <RadioButton Content="{Binding}"
                                     IsChecked="{Binding IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem}}}"/>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <StackPanel Orientation="Horizontal"/>
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
            </ListBox>
        </DataTemplate>
        <Style TargetType="DataGridRow"
               x:Key="SourceModel.RowStyle">
            <Style.Triggers>
                <DataTrigger Value="False">
                    <DataTrigger.Binding>
                        <MultiBinding Converter="{x:Static local:EqualsConverter.Insatance}">
                            <Binding Path="Source"/>
                            <Binding Path="SelectedSource"/>
                        </MultiBinding>
                    </DataTrigger.Binding>
                    <Setter Property="Background" Value="Coral"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>
    <Grid>
        <DataGrid ItemsSource="{Binding SourceModels}" AutoGenerateColumns="False" ItemContainerStyle="{DynamicResource SourceModel.RowStyle}">
            <DataGrid.Columns>
                <DataGridTextColumn Binding="{Binding Id}" Header="Id" IsReadOnly="True"/>
                <DataGridTextColumn Header="Source" Binding="{Binding Source}" IsReadOnly="True" />
                <DataGridTemplateColumn Header="Change source"  CellTemplate="{StaticResource SelectedSource.Template}"/>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>

enter image description here

  • Related