user10184747
user10184747

Reputation:

Can I bind to Background color each DataGridRow?

I use this codes. In this codes, I want to change each row's background color when I click the button. I tried to bind with DataGridRow's background. But I only get BindingExpression.

I know that if I use ObservableCollection as rowdata, it will slove very easy. But I cannot use the collection because I want to bind each column's visibility, too.

I cannot slove to this problem with this code? Please some help.

    <StackPanel>
        <CheckBox IsChecked="{Binding IsChecked}" Content="I change the header of Column A and I hide Column B." Margin="10"/>
        <Button Content="Click!" Click="Button_OnClick" Margin="10" Width="50"/>
        <DataGrid IsReadOnly="True"
                  ItemsSource="{Binding Table}"
                  AutoGeneratingColumn="DataGrid_OnAutoGeneratingColumn"
                  x:Name="DataGrid1" 
Loaded="DataGrid1_Loaded">
            <DataGrid.RowStyle>
                <Style TargetType="DataGridRow">
                    <Setter Property="Background" Value="{Binding MyBackground, Mode=TwoWay}"/>
                </Style>
            </DataGrid.RowStyle>
        </DataGrid>
    </StackPanel>
    public partial class MainWindow : Window
    {
        public ViewModel _viewModel = new ViewModel();

        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = _viewModel;
        }

        private void DataGrid_OnAutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
        {
            BindingOperations.SetBinding(e.Column,
                DataGridColumn.HeaderProperty,
                new Binding($"{nameof(ViewModel.ColumnHeader)}[{e.PropertyName}]")
                {
                    Source = _viewModel
                });

            BindingOperations.SetBinding(e.Column,
                DataGridColumn.VisibilityProperty,
                new Binding($"{nameof(ViewModel.ColumnVisibility)}[{e.PropertyName}].{nameof(BindableValue_ColumnVisible<Visibility>.Value)}")
                {
                    Source = _viewModel
                });
        }

        private void Button_OnClick(object sender, RoutedEventArgs e)
        {

        }

        int mCount = 0;
        string[] displayedColumnOrder;

        private void DataGrid1_Loaded(object sender, RoutedEventArgs e)
        {
            displayedColumnOrder = new string[_viewModel.Table.Columns.Count];

            DataGrid _datagrid = (DataGrid)sender;
            _getColumnOrder(_datagrid.Columns);
        }

        void _getColumnOrder(IEnumerable<DataGridColumn> columnCollection)
        {
            DataGridColumn[] columnArray;
            int columnIndexWorking;
            displayedColumnOrder = new string[columnCollection.Count()];
            columnArray = columnCollection.ToArray();

            foreach (var item_Column in columnCollection)
            {
                columnIndexWorking = item_Column.DisplayIndex;
                displayedColumnOrder[columnIndexWorking] = item_Column.Header.ToString();
            }
        }
    }


    public class ViewModel : BindableBase
    {
        private Brush _myBackground = Brushes.AliceBlue;
        public Brush MyBackground
        {
            get
            {
                return _myBackground;
            }
            set
            {
                _myBackground = value;
                NotifyPropertyChanged(nameof(MyBackground));
            }
        }

        private bool _isChecked = false;
        public bool IsChecked
        {
            get
            {
                return _isChecked;
            }
            set
            {
                _isChecked = value;

                if (value == true)
                {
                    SetHeader();
                    SetVisible();
                }
                else
                {
                    UnSetHeader();
                    UnSetVisible();
                }

                NotifyPropertyChanged(nameof(IsChecked));
            }
        }


        public DataTable Table { get; } = new DataTable();
        public Dictionary<string, string> ColumnHeader { get; } = new Dictionary<string, string>();
        public Dictionary<string, BindableValue_ColumnVisible<Visibility>> ColumnVisibility { get; } = new Dictionary<string, BindableValue_ColumnVisible<Visibility>>();

        public ViewModel()
        {
            Table.Columns.Add("A");
            Table.Columns.Add("B");
            Table.Columns.Add("C");
            Table.Columns.Add("D");
            Table.Columns.Add("E");


            for (int i = 0; i < 10; i++)
            {
                Table.Rows.Add($"A-{i}", $"B-{i}", $"C-{i}", $"D-{i}", $"E-{i}");
            }

            foreach (DataColumn column in Table.Columns)
            {
                ColumnHeader.Add(column.ColumnName, $"Column {column.ColumnName}");
                if (column.ColumnName == "B")
                {
                    ColumnVisibility.Add(column.ColumnName, BindableValue_ColumnVisible.Create(Visibility.Collapsed));
                }
                else
                {
                    ColumnVisibility.Add(column.ColumnName, BindableValue_ColumnVisible.Create(Visibility.Visible));
                }
            }
        }

        public void SetHeader()
        {
            ColumnHeader["A"] = "I changed Column A!!";
            NotifyPropertyChanged(nameof(ColumnHeader));
        }

        public void SetVisible()
        {
            ColumnVisibility["B"].Value = Visibility.Collapsed;
        }

        public void UnSetHeader()
        {
            ColumnHeader["A"] = "Column A";
            NotifyPropertyChanged(nameof(ColumnHeader));
        }

        public void UnSetVisible()
        {
            ColumnVisibility["B"].Value = Visibility.Visible;
        }
    }

    public class BindableValue_ColumnVisible<T> : BindableBase
    {
        public T Value
        {
            get => _value;
            set => SetColumnVisibleProperty(ref _value, value);
        }
        private T _value;

        public BindableValue_ColumnVisible()
        {
        }

        public BindableValue_ColumnVisible(T value)
        {
            Value = value;
        }
    }

    public static class BindableValue_ColumnVisible
    {
        public static BindableValue_ColumnVisible<T> Create<T>(T value) => new BindableValue_ColumnVisible<T>(value);
    }

    public class BindableBase : INotifyPropertyChanged
    {
        protected virtual bool SetColumnVisibleProperty<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
        {
            return SetColumnVisibleProperty(ref field, value, null, propertyName);
        }

        protected virtual bool SetColumnVisibleProperty<T>(ref T field, T value, Action onChanged, [CallerMemberName]string propertyName = null)
        {
            if (EqualityComparer<T>.Default.Equals(field, value)) return false;

            field = value;
            onChanged?.Invoke();
            NotifyPropertyChanged(propertyName);
            return true;
        }

        public event PropertyChangedEventHandler PropertyChanged;
        protected void NotifyPropertyChanged(String info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }
    }

Upvotes: 1

Views: 88

Answers (2)

mm8
mm8

Reputation: 169200

If you add a "MyBackground" column to your DataTable, your current RowStyle and binding should work:

public ViewModel()
{
    Table.Columns.Add("A");
    Table.Columns.Add("B");
    Table.Columns.Add("C");
    Table.Columns.Add("D");
    Table.Columns.Add("E");
    Table.Columns.Add("MyBackground");


    for (int i = 0; i < 10; i++)
    {
        Table.Rows.Add($"A-{i}", $"B-{i}", $"C-{i}", $"D-{i}", $"E-{i}", "Yellow");
    }
...
}

If you set the column to a known string representation of a brush, such as for example "Yellow" or "Red", you don't have to something else. Else, you could use a converter that converts the value in the DataTable to a Brush.

By the way, it's pointless to set the Mode of this Binding to TwoWay.

Upvotes: 0

user8882898
user8882898

Reputation:

public class MyDataTable : System.Data.DataTable {
    private Brush _myBackground = Brushes.AliceBlue;
    public Brush MyBackground {
        get {
            return _myBackground;
        }
        set {
            _myBackground = value;
            NotifyPropertyChanged(nameof(MyBackground));
        }
    }
}

public MyDataTable Table { get; } = new MyDataTable();

<Style TargetType="{x:Type DataGridRow}">
    <Setter Property="Background" Value="{Binding MyBackground }" />
</Style>

Upvotes: 0

Related Questions