Example E1297
Visible to All Users

WPF Data Grid - Change Background Color for Modified Cells

This example demonstrates how to highlight grid cells that were edited by a user.

image

This approach does not highlight cells if you change their values at the data source level. In this case, you can use the DataUpdateFormatCondition instead.

Implementation Details

This example creates invisible unbound columns for each grid column. These Boolean unbound columns contain information on whether the corresponding grid column's cell was modified by a user. The CustomUnboundColumnData event populates unbound columns with data. The specified format condition highlights cells based on data in unbound columns.

Files to Review

Documentation

More Examples

Does this example address your development requirements/objectives?

(you will be redirected to DevExpress.com to submit your response)

Example Code

HighlightChangedCellBehavior.cs(vb)
C#
using DevExpress.Mvvm.UI.Interactivity; using DevExpress.Xpf.Grid; using System; using System.Collections.Generic; using System.Linq; using System.Windows; using System.Windows.Media; namespace HighlightModifiedCells { public class ChangedCellsHighlightBehavior : Behavior<GridControl> { const string UnboundColumnPrefix = "IsEdited_"; Dictionary<Tuple<object, string>, bool> modifiedCells = new Dictionary<Tuple<object, string>, bool>(); Dictionary<Tuple<object, string>, object> originalValues = new Dictionary<Tuple<object, string>, object>(); public static readonly DependencyProperty HighlightBrushProperty = DependencyProperty.Register("HighlightBrush", typeof(Brush), typeof(ChangedCellsHighlightBehavior)); public Brush HighlightBrush { get { return (Brush)GetValue(HighlightBrushProperty); } set { SetValue(HighlightBrushProperty, value); } } protected TableView View { get { return (TableView)AssociatedObject.View; } } protected override void OnAttached() { base.OnAttached(); AssociatedObject.CustomUnboundColumnData += OnGridCustomUnboundColumnData; AssociatedObject.Loaded += OnGridLoaded; } protected override void OnDetaching() { AssociatedObject.CustomUnboundColumnData -= OnGridCustomUnboundColumnData; View.CellValueChanged -= OnViewCellValueChanged; base.OnDetaching(); } void OnGridLoaded(object sender, System.Windows.RoutedEventArgs e) { AssociatedObject.Loaded -= OnGridLoaded; View.CellValueChanged += OnViewCellValueChanged; CreateColumnsAndConditions(); } void OnViewCellValueChanged(object sender, CellValueChangedEventArgs e) { if (!IsServiceColumn(e.Column)) { var fieldName = $"{UnboundColumnPrefix}{e.Column.FieldName}"; var key = Tuple.Create(e.Row, fieldName); object originalValue; bool isModified = true; if (originalValues.TryGetValue(key, out originalValue)) isModified = !Equals(originalValue, e.Value); else originalValues[key] = e.OldValue; AssociatedObject.SetCellValue(e.RowHandle, fieldName, isModified); } } void OnGridCustomUnboundColumnData(object sender, GridColumnDataEventArgs e) { if (IsServiceColumn(e.Column)) { var key = Tuple.Create(AssociatedObject.GetRowByListIndex(e.ListSourceRowIndex), e.Column.FieldName); if (e.IsGetData) { bool res; e.Value = modifiedCells.TryGetValue(key, out res) ? res : false; } if (e.IsSetData) modifiedCells[key] = (bool)e.Value; } } static bool IsServiceColumn(GridColumn column) { return column.FieldName.StartsWith(UnboundColumnPrefix); } void CreateColumnsAndConditions() { foreach (GridColumn column in AssociatedObject.Columns.ToList()) { GridColumn unboundColumn = new GridColumn(); unboundColumn.FieldName = UnboundColumnPrefix + column.FieldName; unboundColumn.UnboundDataType = typeof(bool); unboundColumn.Visible = false; unboundColumn.ShowInColumnChooser = false; AssociatedObject.Columns.Add(unboundColumn); View.FormatConditions.Add(new FormatCondition() { FieldName = column.FieldName, Expression = string.Format("[{0}] = true", unboundColumn.FieldName), Format = new DevExpress.Xpf.Core.ConditionalFormatting.Format() { Background = HighlightBrush } }); } } } }
ViewModel.cs(vb)
C#
using System; using System.Collections.ObjectModel; namespace HighlightModifiedCells { public class ViewModel { public ObservableCollection<Customer> Customers { get; set; } public ViewModel() { Customers = new ObservableCollection<Customer>(); for (int i = 1; i < 30; i++) { Customers.Add(new Customer() { ID = i, Name = "Customer" + i, RegistrationDate = DateTime.Now.AddDays(i) }); } } } public class Customer { public int ID { get; set; } public string Name { get; set; } public DateTime RegistrationDate { get; set; } } }
Window1.xaml
XAML
<Window x:Class="HighlightModifiedCells.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:dxg="http://schemas.devexpress.com/winfx/2008/xaml/grid" xmlns:dxmvvm="http://schemas.devexpress.com/winfx/2008/xaml/mvvm" xmlns:local="clr-namespace:HighlightModifiedCells" Height="500" Width="400"> <Window.DataContext> <local:ViewModel/> </Window.DataContext> <DockPanel> <dxg:GridControl ItemsSource="{Binding Customers}" AutoGenerateColumns="AddNew"> <dxmvvm:Interaction.Behaviors> <local:ChangedCellsHighlightBehavior HighlightBrush="LightPink"/> </dxmvvm:Interaction.Behaviors> <dxg:GridControl.View> <dxg:TableView AutoWidth="True"/> </dxg:GridControl.View> </dxg:GridControl> </DockPanel> </Window>

Disclaimer: The information provided on DevExpress.com and affiliated web properties (including the DevExpress Support Center) is provided "as is" without warranty of any kind. Developer Express Inc disclaims all warranties, either express or implied, including the warranties of merchantability and fitness for a particular purpose. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.

Confidential Information: Developer Express Inc does not wish to receive, will not act to procure, nor will it solicit, confidential or proprietary materials and information from you through the DevExpress Support Center or its web properties. Any and all materials or information divulged during chats, email communications, online discussions, Support Center tickets, or made available to Developer Express Inc in any manner will be deemed NOT to be confidential by Developer Express Inc. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.