Christian Ivicevic
Christian Ivicevic

Reputation: 10885

INotifyPropertyChanged and animation of changing data

In my application I have the scenario where I have a rectangle indicating information based on its width which is just a custom progress bar. I don't have its width bound to a ViewModels property since the changes aren't smooth and the bar would look choppy yet I wanted to have smooth animations when the data changes.

Therefore my event handler that is reacting to the PropertyChanged event of its underlying dependency is notifying the respective properties that should be reflected in the UI but the rectangle is handled differently. Basically it runs

Rectangle.BeginAnimation(FrameworkElement.WidthProperty,
    new DoubleAnimation(width, TimeSpan.FromMilliseconds(200)));

I was curious whether it is reasonable to introduce a property for the width that raises the PropertyChanged event when it changes and then to animate this property so that the rectangle gets animated by animating the width property in my ViewModel. Is it even possible to animate custom properties in that scenario?

Upvotes: 0

Views: 202

Answers (1)

Clemens
Clemens

Reputation: 128061

You may create an attached property TargetWidth that animates the Width property of a FrameworkElement when set.

public static class FrameworkElementExtension
{
    public static readonly DependencyProperty TargetWidthProperty =
        DependencyProperty.RegisterAttached(
            "TargetWidth",
            typeof(double),
            typeof(FrameworkElementExtension),
            new PropertyMetadata(TargetWidthPropertyChanged));

    public static double GetTargetWidth(this FrameworkElement obj)
    {
        return (double)obj.GetValue(TargetWidthProperty);
    }

    public static void SetTargetWidth(this FrameworkElement obj, double value)
    {
        obj.SetValue(TargetWidthProperty, value);
    }

    private static void TargetWidthPropertyChanged(
        DependencyObject obj, DependencyPropertyChangedEventArgs e)
    {
        var element = obj as FrameworkElement;
        if (element != null)
        {
            if (double.IsNaN(element.Width))
            {
                element.Width = 0;
            }

            element.BeginAnimation(
                FrameworkElement.WidthProperty,
                new DoubleAnimation((double)e.NewValue, TimeSpan.FromSeconds(0.2)));
        }
    }
}

You may now either directly set the TargetWidth like

Rectangle.SetTargetWidth(width);

or bind it to a view model property:

<Rectangle ... local:FrameworkElementExtension.TargetWidth="{Binding RectangleWidth}" />

Upvotes: 2

Related Questions