Search code examples
c#wpfasynchronousdata-binding

How to avoid flickering when using an asynchronous binding


I've created an example to illustrate my problem.

ViewModel:

public class VM : INotifyPropertyChanged
{
    private double _value = 1;
    public double Value
    {
        get { return _value; }
        set
        {
            _value = value; 
            OnPropertyChanged();
        }
    }

    public VM()
    {
        var timer = new DispatcherTimer();
        timer.Interval = TimeSpan.FromTicks(1);
        timer.Tick += (s, e) => { Value += 1; };
        timer.Start();
    }

    // OnPropertyChanged stuff ... 
    }
}

View:

<Window.DataContext>
    <namespace:VM/>
</Window.DataContext>
<Grid>
    <TextBox Text="{Binding Value, IsAsync=True, FallbackValue=Test}"/>
</Grid>

When running my application the text in the textbox flickers. During the update process the FallbackValue is displayed, which makes no sense to me.

Does anyone knows the purposes or what are the benefits that during the update process the FallbackValue is displayed? Is there a way to display the old Value during an async update process?


Solution

  • I've found an approach to avoid flickering by just inheriting from textbox and overriding it's textproperty-metadata.

    Custom TextBoxControl

    public class CustomTextBox : TextBox
    {
        static CustomTextBox()
        {
            TextProperty.OverrideMetadata(typeof(CustomTextBox), new FrameworkPropertyMetadata(null, null, CoerceChanged));
        }
    
        private static object CoerceChanged(DependencyObject d, object basevalue)
        {
            var tb = d as TextBox;
            if (basevalue == null)
            {
                return tb.Text;
            }
            return basevalue;
        }
    }
    

    View

    <Window.DataContext>
        <namespace:VM/>
    </Window.DataContext>
    <Grid>
        <namespace:CustomTextBox Text="{Binding Value, IsAsync=True}"/>
    </Grid>
    

    It's important to have the text-binding without a fallbackvalue. So during update process the text is set to the textproperty defalut value - so in this case to null.

    The CoerceChanged handler checks whether the new value is null. If it's so he returns the old value so that during update process there is still the old value displayed.