I had a look through the source code and the BindingExpressionBase itself is aware of this through a property called NeedsUpdate. But this property is internal so you would have to use reflection to get it.
However, you won't be able to monitor this property in any easy way. So the way I see it, you would need to use both of the events TextChanged and SourceUpdated to know when NeedsUpdate might have changed.
Update
I created an attached behavior that does this, it can be used to monitor pending updates on any DependencyProperty. Note that NotifyOnSourceUpdated must be set to true.
Uploaded a small sample project here: PendingUpdateExample.zip
Example
<TextBox Text="{Binding ElementName=textBoxSource, Path=Text, NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged, Delay=1000}" ab:UpdatePendingBehavior.MonitorPendingUpdates="{x:Static TextBox.TextProperty}"> <TextBox.Style> <Style TargetType="TextBox"> <Style.Triggers> <Trigger Property="ab:UpdatePendingBehavior.HasPendingUpdates" Value="True"> <Setter Property="Background" Value="Green"/> </Trigger> </Style.Triggers> </Style> </TextBox.Style> </TextBox>
UpdatePendingBehavior
public class UpdatePendingBehavior { #region MonitorPendingUpdates public static DependencyProperty MonitorPendingUpdatesProperty = DependencyProperty.RegisterAttached("MonitorPendingUpdates", typeof(DependencyProperty), typeof(UpdatePendingBehavior), new UIPropertyMetadata(null, MonitorPendingUpdatesChanged)); public static DependencyProperty GetMonitorPendingUpdates(FrameworkElement obj) { return (DependencyProperty)obj.GetValue(MonitorPendingUpdatesProperty); } public static void SetMonitorPendingUpdates(FrameworkElement obj, DependencyProperty value) { obj.SetValue(MonitorPendingUpdatesProperty, value); } public static void MonitorPendingUpdatesChanged(DependencyObject target, DependencyPropertyChangedEventArgs e) { DependencyProperty property = e.NewValue as DependencyProperty; if (property != null) { FrameworkElement element = target as FrameworkElement; element.SourceUpdated += elementProperty_SourceUpdated; if (element.IsLoaded == true) { SubscribeToChanges(element, property); } element.Loaded += delegate { SubscribeToChanges(element, property); }; element.Unloaded += delegate { UnsubscribeToChanges(element, property); }; } } private static void SubscribeToChanges(FrameworkElement element, DependencyProperty property) { DependencyPropertyDescriptor propertyDescriptor = DependencyPropertyDescriptor.FromProperty(property, element.GetType()); propertyDescriptor.AddValueChanged(element, elementProperty_TargetUpdated); } private static void UnsubscribeToChanges(FrameworkElement element, DependencyProperty property) { DependencyPropertyDescriptor propertyDescriptor = DependencyPropertyDescriptor.FromProperty(property, element.GetType()); propertyDescriptor.RemoveValueChanged(element, elementProperty_TargetUpdated); } private static void elementProperty_TargetUpdated(object sender, EventArgs e) { FrameworkElement element = sender as FrameworkElement; UpdatePendingChanges(element); } private static void elementProperty_SourceUpdated(object sender, DataTransferEventArgs e) { FrameworkElement element = sender as FrameworkElement; if (e.Property == GetMonitorPendingUpdates(element)) { UpdatePendingChanges(element); } } private static void UpdatePendingChanges(FrameworkElement element) { BindingExpressionBase beb = BindingOperations.GetBindingExpressionBase(element, GetMonitorPendingUpdates(element)); BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic; PropertyInfo needsUpdateProperty = beb.GetType().GetProperty("NeedsUpdate", bindingFlags); SetHasPendingUpdates(element, (bool)needsUpdateProperty.GetValue(beb)); } #endregion // MonitorPendingUpdates #region HasPendingUpdates public static DependencyProperty HasPendingUpdatesProperty = DependencyProperty.RegisterAttached("HasPendingUpdates", typeof(bool), typeof(UpdatePendingBehavior), new UIPropertyMetadata(false)); public static bool GetHasPendingUpdates(FrameworkElement obj) { return (bool)obj.GetValue(HasPendingUpdatesProperty); } public static void SetHasPendingUpdates(FrameworkElement obj, bool value) { obj.SetValue(HasPendingUpdatesProperty, value); } #endregion // HasPendingUpdates }
Another way could be to use a MultiBinding that binds both to the source and the target and compares their values in a converter. Then you could change the Background in the Style. This assumes that you don't convert the value. Example with two TextBoxes
<TextBox Text="{Binding ElementName=textBoxSource, Path=Text, UpdateSourceTrigger=PropertyChanged, Delay=2000}"> <TextBox.Style> <Style TargetType="TextBox"> <Style.Triggers> <DataTrigger Value="False"> <DataTrigger.Binding> <MultiBinding Converter="{StaticResource IsTextEqualConverter}"> <Binding RelativeSource="{RelativeSource Self}" Path="Text"/> <Binding ElementName="textBoxSource" Path="Text"/> </MultiBinding> </DataTrigger.Binding> <Setter Property="Background" Value="Green"/> </DataTrigger> </Style.Triggers> </Style> </TextBox.Style> </TextBox> <TextBox Name="textBoxSource"/>
IsTextEqualConverter
public class IsTextEqualConverter : IMultiValueConverter { public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) { return values[0].ToString() == values[1].ToString(); } public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) { throw new NotSupportedException(); } }