Hi guys!
The missed binding updating after coercing a DP value was resolved only partially in my previous post. In fact the issue is still present when the binded DP type is a String!
Below my sample application screenshot downloadable here.

And, sure, here you are the new definitely fix 😉

        public string MyValue
        {
            get { return (string)GetValue(MyValueProperty); }
            set { SetValue(MyValueProperty, value); }
        }
        public static readonly DependencyProperty MyValueProperty =
            DependencyProperty.Register("MyValue", typeof(string), typeof(Window1), new UIPropertyMetadata("50", new PropertyChangedCallback(MyValueChanged), new CoerceValueCallback(MyValueCoerceValue)));

        private static void MyValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            Window1 w1 = d as Window1;
            w1._txtBox.GetBindingExpression(TextBox.TextProperty).UpdateTarget();
        }

        private static object MyValueCoerceValue(DependencyObject d, object value)
        {
            string intValue = (string)value;

            if (Int32.Parse(intValue) < 0)
                intValue = "0";
            else if (Int32.Parse(intValue) > 100)
                intValue = "100";

            Window1 w1 = d as Window1;
            w1._txtBox.GetBindingExpression(TextBox.TextProperty).UpdateTarget();

            return intValue;
        }

You are may asking “why it is necessary forcing binding UpdateTarget() both in CoerceValue and PropertyChanged callbacks”?

  • UpdateTarget() in PropertyChanged: in this way we ensure that the displayed text is updated every time MyValue DP has been changed. However, what happens when the current value is “100” and the user insert “1000”? The CoerceValue sets MyValue DP to 100 but, since the old value (100) is equal to new value (100), the PropertyChanged is not called! Consequently, the TextBox still displays the last typed value (1000)!
  • UpdateTarget() in CoerceValue: in this way we cover the scenario in which the current value is “100” and the user insert a value greater than 100 (e.g. 1000).
  • Honestly, I didn’t understood the reason why in case of “int” DP property a single call of UpdateTarget() on CoerceValue is sufficient to update the displayed value.

    Happy coding!
    Marzio.


    Please, for definitely fix see the second part of this article 😉

    Hi!
    Today I spent 2 hours of my coding in understanding the reason why a TextBox didn’t display a new value set by CoerceValue Callback!

    Click here to download the example.

    This is the XAML code containing the Text property binding.

    <Window x:Class="TextBindingAndCoerceValue.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        DataContext="{Binding RelativeSource={RelativeSource Self}}"
        Title="Binding and CoerceValue" 
        Height="300" 
        Width="300">
        
        <StackPanel Orientation="Vertical">
            <StackPanel Orientation="Horizontal">
                <Label Content="Insert Value (0-100):" VerticalAlignment="Center"/>
                <TextBox Name="_txtBox" Margin="5" Text="{Binding MyValue, Mode=TwoWay}" HorizontalAlignment="Stretch" Width="152"/>
            </StackPanel>
            <Button Margin="5" Content="Set New Value"/>
        </StackPanel>
        
    </Window>
    

    And here you are the code behind (affected with described issue).

        public partial class Window1 : Window
        {
    
            public int MyValue
            {
                get { return (int)GetValue(MyValueProperty); }
                set { SetValue(MyValueProperty, value); }
            }
            public static readonly DependencyProperty MyValueProperty =
                DependencyProperty.Register("MyValue", typeof(int), typeof(Window1), new UIPropertyMetadata(0, new PropertyChangedCallback(MyValueChanged), new CoerceValueCallback(MyValueCoerceValue)));
    
            private static void MyValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
            {
            }
    
            private static object MyValueCoerceValue(DependencyObject d, object value)
            {
                int intValue = (int)value;
    
                if (intValue < 0)
                    intValue = 0;
                else if (intValue > 100)
                    intValue = 100;
    
                return intValue;
            }
    
    
            public Window1()
            {
                InitializeComponent();
            }
        }
    

    The problem is that MyValue Dependency Property is properly updated when inserting a value less than 0 or greater than 100, but the TextBlock still display the just typed value!
    Honestly I didn’t understood the real cause of the problem and every WPF developers should expect TwoWay binding to display coerced value! Instead, even with a binding, the text block is still presenting what is typed into it ignoring the update!

    As developer, you need to force a target update on the binding (via UpdateTarget()) when the coersion fails if you want to display the coerced value. Here you are the problem fixing:

    
            private static object MyValueCoerceValue(DependencyObject d, object value)
            {
                int intValue = (int)value;
    
                if (intValue < 0)
                    intValue = 0;
                else if (intValue > 100)
                    intValue = 100;
    
                Window1 w1 = d as Window1;
                w1._txtBox.GetBindingExpression(TextBox.TextProperty).UpdateTarget();
    
                return intValue;
            }
    
    

    Happy coding,
    Marzio.