Is it possible to bind WPF DataGrid's RowState property to a property in the codebehind collection?

Dave Cotton 41 Reputation points
2021-12-24T00:03:07.887+00:00

.Net 4.6.1

Given an ObservableCollection OC that is a collection of MyDisplayGrid MDG, and that OC has been set as the DataGrid's ItemSource

Is it possible to bind (not display on the grid) the RowState property of the DataGrid to a property of MyDisplayGrid?

Thanks,
Nottoc

Windows Presentation Foundation
Windows Presentation Foundation
A part of the .NET Framework that provides a unified programming model for building line-of-business desktop applications on Windows.
2,700 questions
XAML
XAML
A language based on Extensible Markup Language (XML) that enables developers to specify a hierarchy of objects with a set of properties and logic.
778 questions
{count} votes

Accepted answer
  1. Peter Fleischer (former MVP) 19,306 Reputation points
    2021-12-31T07:02:55.937+00:00

    Hi,
    you can use DataTable and RowState of DataRows. try following demo:

    <Window x:Class="WpfApp1.Window093"  
            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:WpfApp093"  
            mc:Ignorable="d"  
            Title="DaveCotton-2388_211224" Height="450" Width="800">  
      <Window.DataContext>  
        <local:ViewModel/>  
      </Window.DataContext>  
      <Window.Resources>  
        <local:RowStateToBrushConverter x:Key="conv" />  
      </Window.Resources>  
      <Grid>  
        <DataGrid AutoGenerateColumns="False"   
                  Margin="5"  
                  ItemsSource="{Binding View}">  
          <DataGrid.RowStyle>  
            <Style TargetType="DataGridRow">  
              <Setter Property="Background" Value="{Binding RowState, Converter={StaticResource conv}}"/>  
            </Style>  
          </DataGrid.RowStyle>  
          <DataGrid.Columns>  
            <DataGridTextColumn Binding="{Binding ID}" Header="ID"/>  
            <DataGridTextColumn Binding="{Binding Name}" Header="Name"/>  
          </DataGrid.Columns>  
        </DataGrid>  
      </Grid>  
    </Window>  
    

    and classes:

    using System;  
    using System.Collections.ObjectModel;  
    using System.ComponentModel;  
    using System.Data;  
    using System.Globalization;  
    using System.Runtime.CompilerServices;  
    using System.Windows;  
    using System.Windows.Data;  
    using System.Windows.Media;  
      
    namespace WpfApp093  
    {  
      public class ViewModel  
      {  
        public ViewModel() => FillDataTable(dt);  
        private DataTable dt = new DataTable();  
        private CollectionViewSource cvs = new CollectionViewSource();  
        public ICollectionView View { get => cvs.View; }  
        private void FillDataTable(DataTable dt)  
        {  
          dt.Columns.Add("ID", typeof(int));  
          dt.Columns.Add("Name", typeof(string));  
          Random rnd = new Random();  
          for (int i = 10; i < 30; i++) dt.Rows.Add(i, $"Name {rnd.Next(10,100)}");  
          dt.AcceptChanges();  
          ObservableCollection<Data> col = new ObservableCollection<Data>();  
          foreach (DataRow r in dt.Rows) col.Add(new Data(r));  
          cvs.Source = col;  
        }  
      }  
      
      public class Data : INotifyPropertyChanged  
      {  
        public Data(DataRow drow) => row = drow;  
        DataRow row;  
        public int ID { get => (int)row["ID"]; }  
        public string Name  
        {  
          get => row["Name"].ToString();  
          set  
          {  
            row["Name"] = value;  
            OnPropertyChanged(nameof(RowState));  
          }  
        }  
        public DataRowState RowState { get => row.RowState; }  
      
        public event PropertyChangedEventHandler PropertyChanged;  
        private void OnPropertyChanged([CallerMemberName] string propName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));  
      }  
      
      public class RowStateToBrushConverter : IValueConverter  
      {  
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)  
        {  
          if (value != null)  
          {  
            switch ((DataRowState)value)  
            {  
              case DataRowState.Detached:  
                return Brushes.Red;  
              case DataRowState.Unchanged:  
                return Brushes.LightGreen;  
              case DataRowState.Added:  
                return Brushes.Yellow;  
              case DataRowState.Deleted:  
                return Brushes.Pink;  
              case DataRowState.Modified:  
                return Brushes.LightPink;  
              default:  
                return Brushes.White;  
            }  
          }  
          return Brushes.White;  
        }  
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) =>  
          new NotImplementedException();  
      }  
    }  
    

    Result:

    161584-x.gif

    0 comments No comments

3 additional answers

Sort by: Most helpful
  1. Ken Tucker 5,846 Reputation points
    2021-12-24T00:49:54.077+00:00

    The WPF datagrid row does not have a RowState property. It has a IsNewItem property. Typically the object the DataGrids ItemsSource is bound to keeps track of if the items RowState


  2. Dave Cotton 41 Reputation points
    2021-12-24T16:56:54.453+00:00

    Additional details:
    In the code behind the collection is defined like this:

                 private ObservableCollection<ControlServerRow> controlServerRows = new ObservableCollection<ControlServerRow>();
                 public ObservableCollection<ControlServerRow> ControlServerRows
                 {
                     get { return controlServerRows; }
                 }
    

    The ControlServerRow is defined like this:

             public class ControlServerRow : INotifyPropertyChanged
             {
                 private int id;
                 public int ID
                 {
                     get { return id; }
                     set
                     {
                         if (id != value)
                         {
                             id = value;
                             NotifyPropertyChanged();
                         }
                     }
                 }
    
                 private string environmentName;
                 public string EnvironmentName
                 {
                     get { return environmentName; }
                     set
                     {
                         if (environmentName != value)
                         {
                             environmentName = value;
                             NotifyPropertyChanged();
                         }
                     }
                 }
             }
    

    The Grid xaml:

            <DataGrid ItemsSource="{Binding ControlServerRows}" AutoGenerateColumns="False" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="5,30,5,50">
                <DataGrid.Columns>
                    <DataGridTextColumn Binding="{Binding ID}" Visibility="Collapsed"/>
                    <DataGridTextColumn Header="Environment Name" Binding="{Binding EnvironmentName}" Width="auto"/>
                </DataGrid.Columns>
            </DataGrid>
    

    What I would like to accomplish is to add another property to ControlServerRow (type unknown). And that property would contain the RowState. At the moment I'm exploring using a converter that would somehow be able to reference the RowState.

    The RowState is the built in property maintained by the DataGrid as described in this post:

    how-to-set-datagrids-row-background-based-on-a-property-value-using-data-bindi
    HTH

    0 comments No comments

  3. Hui Liu-MSFT 47,101 Reputation points Microsoft Vendor
    2021-12-31T02:10:59.87+00:00

    Here is an example of using the converter for the background color of the DataGrid row, you could try it for reference.
    MainWindow.xaml:

    <Window.Resources>  
            <local:StringToBrushConverter x:Key="stringToBrush" />  
        </Window.Resources>  
        <Grid>  
            <DataGrid ItemsSource="{Binding ControlServerRows}" AutoGenerateColumns="False" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="5,30,5,50">  
                <DataGrid.RowStyle>  
                    <Style TargetType="DataGridRow">  
                        <Setter Property="Background" Value="{Binding Path = State, Converter={StaticResource stringToBrush}}"/>  
                    </Style>  
                </DataGrid.RowStyle>  
                <DataGrid.Columns>  
                    <DataGridTextColumn Header="Id" Binding="{Binding ID}"  />  
                    <DataGridTextColumn Header="Environment Name" Binding="{Binding EnvironmentName}" Width="auto"/>  
                    <DataGridTextColumn Header="State" Binding="{Binding State}" Width="auto"/>  
                </DataGrid.Columns>  
            </DataGrid>  
        </Grid>  
    

    MainWindow.xaml.cs:

    using System;  
    using System.Collections.ObjectModel;  
    using System.ComponentModel;  
    using System.Globalization;  
    using System.Windows;  
    using System.Windows.Data;  
    using System.Windows.Media;  
    namespace RowState  
    {  
      public partial class MainWindow : Window  
      {  
        public MainWindow()  
        {  
          InitializeComponent();  
          DataContext=new ViewModel();  
        }  
      }  
      public class ViewModel  
      {  
        private ObservableCollection<ControlServerRow> controlServerRows;  
        public ObservableCollection<ControlServerRow> ControlServerRows  
        {  
          get { return controlServerRows; }  
        }  
        public ViewModel()  
        {  
          controlServerRows = new ObservableCollection<ControlServerRow>();  
          controlServerRows.Add(new ControlServerRow() { ID = 1, EnvironmentName = "name1",  State="state1" });  
          controlServerRows.Add(new ControlServerRow() { ID = 2, EnvironmentName = "name2",  State = "state1" });  
          controlServerRows.Add(new ControlServerRow() { ID = 3, EnvironmentName = "name3",  State = "state2" });  
          controlServerRows.Add(new ControlServerRow() { ID = 4, EnvironmentName = "name4",  State = "state1" });  
        }  
      }  
      public class StringToBrushConverter : IValueConverter  
      {  
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)  
        {  
          var val = (string)value;  
          return new SolidColorBrush(val == "state1" ? Colors.LightBlue : Colors.LightPink);  
        }  
      
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)  
        {  
          throw new NotImplementedException();  
        }  
      }  
      public class ControlServerRow : INotifyPropertyChanged  
      {  
        private string state;  
        public string State  
        {  
          get { return state; }  
          set  
          {  
            if (state != value)  
            {  
              state = value;  
              OnPropertyChanged("State");  
            }  
          }  
        }  
        private int id;  
        public int ID  
        {  
          get { return id; }  
          set  
          {  
            if (id != value)  
            {  
              id = value;  
              OnPropertyChanged("ID");  
            }  
          }  
        }  
        private string environmentName;  
        public string EnvironmentName  
        {  
          get { return environmentName; }  
          set  
          {  
            if (environmentName != value)  
            {  
              environmentName = value;  
              OnPropertyChanged("EnvironmentName");  
            }  
          }  
        }  
        public event PropertyChangedEventHandler PropertyChanged;  
        public void OnPropertyChanged(String info)  
        {  
          if (PropertyChanged != null)  
          {  
            PropertyChanged(this, new PropertyChangedEventArgs(info));  
          }  
        }  
      }  
    }  
    

    The result:
    161606-1.gif


    If the response is helpful, please click "Accept Answer" and upvote it.
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    0 comments No comments