2

In my XAML I have the following:

<DataTemplate x:Key="ItemTemplate">
        <DockPanel Width="Auto">
            <Button Click="SelectMovie_Click" DockPanel.Dock="Top">
                <Button.Template>
                    <ControlTemplate >
                        <Image Source="{Binding image}"/>
                    </ControlTemplate>
                </Button.Template>                   
                <Button.Triggers>
                    <EventTrigger RoutedEvent="Button.Click">
                        <BeginStoryboard>
                            <Storyboard>
                                <local:GridLengthAnimation
                                    Storyboard.Target="{Binding ElementName=col2}"
                                    Storyboard.TargetProperty="Width"
                                    Duration="0:0:2"/>
                            </Storyboard>
                        </BeginStoryboard>
                    </EventTrigger>
                </Button.Triggers>
            </Button>
            <TextBlock Text="{Binding title}" HorizontalAlignment="Center" DockPanel.Dock="Bottom"/>
        </DockPanel>
    </DataTemplate>

<Grid Grid.Row="2" >
        <Grid.ColumnDefinitions>
            <ColumnDefinition Name="col1"  Width="{Binding ElementName=root, Path=DataContext.gla.LeftGridWidth}"/>
            <ColumnDefinition Name="col2" Width="{Binding ElementName=root, Path=DataContext.gla.RightGridWidth}"/>
        </Grid.ColumnDefinitions>
         ...
         ...
</Grid>

gla is a GridLengthAnimationObject.

I am getting the above error when I try to set my Dependency Property

public class GridLengthAnimation : AnimationTimeline
{
    public override Type TargetPropertyType
    {
        get
        {
            return typeof(GridLength);
        }
    }

    protected override System.Windows.Freezable CreateInstanceCore()
    {
        return new GridLengthAnimation();
    }

    public GridLengthAnimation()
    {
        LeftGridWidth = new GridLength(7, GridUnitType.Star);
        RightGridWidth = new GridLength(0, GridUnitType.Star);
    }

    public static readonly DependencyProperty LeftGridWidthProperty = DependencyProperty.Register("LeftGridWidth", typeof(GridLength), typeof(GridLengthAnimation));
    public GridLength LeftGridWidth
    {
        get { return (GridLength)this.GetValue(LeftGridWidthProperty); }
        set { this.SetValue(LeftGridWidthProperty, value); }
    }

    public static readonly DependencyProperty RightGridWidthProperty = DependencyProperty.Register("RightGridWidth", typeof(GridLength), typeof(GridLengthAnimation));
    public GridLength RightGridWidth
    {

        get { return (GridLength)this.GetValue(RightGridWidthProperty); }
        set { this.SetValue(RightGridWidthProperty, value); }
    }

    public override object GetCurrentValue(object defaultOriginValue, object defaultDestinationValue, AnimationClock animationClock)
    {
        double rightGridVal = ((GridLength)GetValue(GridLengthAnimation.RightGridWidthProperty)).Value;
        double leftGridVal = ((GridLength)GetValue(GridLengthAnimation.LeftGridWidthProperty)).Value;

        RightGridWidth = rightGridVal == 0 ? new GridLength(3, GridUnitType.Star) : new GridLength(0, GridUnitType.Star);

        return RightGridWidth;
    }        
}

Error occurs here:

 RightGridWidth = rightGridVal == 0 ? new GridLength(3, GridUnitType.Star) : new GridLength(0, GridUnitType.Star);

Stack Trace

System.InvalidOperationException: Cannot set a property on object   'VideoManager.GridLengthAnimation' because it is in a read-only state.
at System.Windows.DependencyObject.SetValueCommon(DependencyProperty dp, Object value,   PropertyMetadata metadata, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue,   OperationType operationType, Boolean isInternal)
at System.Windows.DependencyObject.SetValue(DependencyProperty dp, Object value)
at VideoManager.GridLengthAnimation.set_RightGridWidth(GridLength value) in    c:\Users\Giri\Documents\Visual Studio   2013\Projects\VideoManager\VideoManager\GridLengthAnimation.cs:line 47
at VideoManager.GridLengthAnimation.GetCurrentValue(Object defaultOriginValue, Object    defaultDestinationValue, AnimationClock animationClock) in c:\Users\Giri\Documents\Visual Studio   2013\Projects\VideoManager\VideoManager\GridLengthAnimation.cs:line 56
A first chance exception of type 'System.InvalidOperationException' occurred in WindowsBase.dll     

In my LeftGrid I have a number of Buttons. The LeftGrid has a default width of 7* while the RightGrid is initially set to 0* (not visible). When a Button is clicked in the LeftGrid, the RightGrid should expand to a width of 3*. This expansion of the RightGrid should be animated. Finally if the RightGrid is expanded and a button in the LeftGrid is clicked twice in succession, the RightGrid should shrink back to 0*.

  • 1
    For what its worth, your `Register` call is missing the metadata at the end. I *doubt* that would cause the error, but it might be worth a shot. – BradleyDotNET Jan 05 '15 at 17:21
  • Can you please add the exception details with full stack trace? That would go a long way in helping solve the issue. – Drew Marsh Jan 06 '15 at 00:04
  • @DrewMarsh I added some extra information. –  Jan 06 '15 at 07:52
  • Why are you trying to set the value of the `RightGridWidth` property while the animation is running? – Clemens Jan 06 '15 at 13:13
  • @Giri What about the exception's type and message? If you're broken in the debugger when it happens, just go to the immediate window and do $exception.ToString() and paste the output of that into here. – Drew Marsh Jan 06 '15 at 18:52
  • @DrewMarsh I set a `try/catch` block around the offending line and did as you said. I copied the output above. I hope that is what you were asking for. –  Jan 06 '15 at 23:43
  • @Clemens I don't think I have the right understanding of how to achieve what I want. I have provided some additional details of my `XAML` and how it is interacting with this `GridLengthAnimation` class. –  Jan 06 '15 at 23:50
  • @Giri How about adding a few words about what you are actually trying to achieve? Then we wouldn't have to guess that from your XAML. Maybe there is an easier approach. – Clemens Jan 07 '15 at 08:52
  • @Clemens I have added information about what I am trying to achieve at the end of the question. –  Jan 07 '15 at 13:53
  • Not sure if this will help but I read this in the docs for `Freezable` `It's very important that you begin each Freezable method you override with a call to the base implementation.` – Tejas Sharma Jan 07 '15 at 14:05

1 Answers1

1

The simplest implementation of a GridLengthAnimation could look like shown below. It only adds a To property (like e.g. DoubleAnimation has), but no From or By properties. It can hence only animate a property from its current value to a specified target value.

public class GridLengthAnimation : AnimationTimeline
{
    public static readonly DependencyProperty ToProperty =
        DependencyProperty.Register(
            "To", typeof(GridLength), typeof(GridLengthAnimation));

    public GridLength To
    {
        get { return (GridLength)GetValue(ToProperty); }
        set { SetValue(ToProperty, value); }
    }

    public override Type TargetPropertyType
    {
        get { return typeof(GridLength); }
    }

    protected override Freezable CreateInstanceCore()
    {
        return new GridLengthAnimation();
    }

    public override object GetCurrentValue(
        object defaultOriginValue, object defaultDestinationValue,
        AnimationClock animationClock)
    {
        var from = (GridLength)defaultOriginValue;

        if (from.GridUnitType != To.GridUnitType ||
            !animationClock.CurrentProgress.HasValue)
        {
            return from;
        }

        var p = animationClock.CurrentProgress.Value;

        return new GridLength(
            (1d - p) * from.Value + p * To.Value,
            from.GridUnitType);
    }
}

You would use it like this:

<local:GridLengthAnimation
    Storyboard.Target="{Binding ElementName=col2}"
    Storyboard.TargetProperty="Width"
    Duration="0:0:2" To="3*"/>
Clemens
  • 123,504
  • 12
  • 155
  • 268
  • Thanks Clemens. I need an `If` condition to be satisfied before I do the expansion and contraction of the `RightGrid`. Could you please tell me where in the code I could insert this? –  Jan 07 '15 at 21:11
  • You won't need that as long as you can set the `To` value. What should it be good for? – Clemens Jan 07 '15 at 21:14
  • The RightGrid should only contract when the Right Grid is expanded and if the same button was clicked twice in succession, not simply when any button is clicked and the Right Grid is already expanded. –  Jan 07 '15 at 21:35
  • An animation should not know which property it is animating, and in which direction under which conditions. It should only provide a time dependent value, nothing more. Your condition check belongs somewhere else. Instead of the Click event trigger in XAML you might for example add a Click event handler that sets the animation's To value depending on the current condition. – Clemens Jan 07 '15 at 22:23