Question

I've written code to change the foreground property of a DataGrid cell if the row containing that cell meets a given rule (let's say its text must have the value "Incomplete"). I can make this work fairly easy by catching the LoadingRow event in code behind and writing my logic there, but I feel like this is not a very elegant MVVM implementation. Here's the code:

// Sets the foreground color of th 5th cell to red if the text in the cell corresponds 
// to a value specified in the ViewModel.
private void dgProfile_LoadingRow(object sender, DataGridRowEventArgs e)
    {

        this.dgProfile.SelectedIndex = e.Row.GetIndex();
        DataGridColumn column = this.dgProfile.Columns[4];
        FrameworkElement fe = column.GetCellContent(e.Row);
        FrameworkElement result = GetParent(fe, typeof(DataGridCell));
        if (result != null)
        {
            DataGridCell cell = (DataGridCell)result;
            if (((TextBlock)cell.Content).Text == (this.DataContext as ProfileViewModel).strIncompleteActivityStatus) cell.Foreground = new SolidColorBrush(Colors.Red);
            else cell.Foreground = new SolidColorBrush(Colors.Black);
        }

    }
    private FrameworkElement GetParent(FrameworkElement child, Type targetType)
    {
        object parent = child.Parent;
        if (parent != null)
        {
            if (parent.GetType() == targetType)
            {
                return (FrameworkElement)parent;
            }
            else
            {
                return GetParent((FrameworkElement)parent, targetType);
            }
        }
        return null;
    }

Can someone tell me if there's a better way to implement this using the MVVM Light toolkit, perhaps through RelayCommand and some clever data binding?

Thanks in advance for the help!

Was it helpful?

Solution

You can define a template column and bind the foreground property to a value converter that returns the appropriate SolidColorBrush.

For example:

<data:DataGrid.Columns>
     <data:DataGridTemplateColumn>
                <data:DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding MyProperty}"
                                   Foreground="{Binding MyProperty, Converter={StaticResource MyConverter}}"/>

                    </DataTemplate>
                </data:DataGridTemplateColumn.CellTemplate>
            </data:DataGridTemplateColumn>
</data:DataGrid.Columns>

And the converter:

public class MyConverter : System.Windows.Data.IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value != null)
        {
            string propertyValue = (string)value;

            if (propertyValue == strIncompleteActivityStatus)
                return new SolidColorBrush(Colors.Red);
            else
                return new SolidColorBrush(Colors.Black);
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

More details here:

DataGrid cell color based on cell value

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top