Question

I have a custom class say 'MyCanvas' derived from wpf Canvas class. MyCanvas has a Dependency Property 'Scale' which specify the scale transform for the canvas. Now when the value of Scale changes I want to animate the transform from old value to new value. for that I am using LayoutTransform.BeginAnimation(...) method.

Code:

//This represents the time it will take to zoom
Duration zoomDuration = new Duration(TimeSpan.Parse("0:0:0.3"));

//Set up animation for zooming
DoubleAnimationUsingKeyFrames scaleAnimation = new DoubleAnimationUsingKeyFrames();
scaleAnimation.Duration = zoomDuration;
scaleAnimation.KeyFrames = GetAnimationSplines(newScale);
scaleAnimation.Completed += new EventHandler(
    (sender, e) => Scale = newScale);

// Start the scale (zoom) animations
LayoutTransform.BeginAnimation(ScaleTransform.ScaleXProperty, scaleAnimation);
LayoutTransform.BeginAnimation(ScaleTransform.ScaleYProperty, scaleAnimation);

XMAL:

<Grid>
    <ItemsControl x:Name="Items">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <local:MyCanvas Scale="{Binding Scale, Mode=TwoWay}">
                    <local:MyCanvas.LayoutTransform UseLayoutRounding="True">
                        <ScaleTransform ScaleX="{Binding Scale, Mode=TwoWay}" 
                                        ScaleY="{Binding Scale, Mode=TwoWay}"/>
                    </local:MyCanvas.LayoutTransform>
                 </local:MyCanvas>
             </ItemsPanelTemplate>
         </ItemsControl.ItemsPanel>
    </ItemsControl>
</Grid>

But after executing this code, the binding of ScaleX and ScaleY with Scale ( a property in viewmodel) is breaking i.e. changing value of Scale does not change scale on canvas.

Error Message (using Snoop):

System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=Scale; DataItem=null; target element is 'ScaleTransform' (HashCode=796423); target property is 'ScaleX' (type 'Double')

System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=Scale; DataItem=null; target element is 'ScaleTransform' (HashCode=796423); target property is 'ScaleY' (type 'Double')

Please let me know if any one has solution for this. Thanks

Was it helpful?

Solution 2

Well, Today I was trying some thing and suddenly the issue got resolved. I did not understand how it start working. I made following changes to the code, which I tried earlier too.

scaleAnimation.FillBehavior = FillBehavior.Stop;

Can anyone explain this to me. Thanks.

OTHER TIPS

This is not a solution to above problem but a working sample WPF Application to reproduce the above mention issue.

XAML:

<Window x:Class="TestWpfApplication.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="*" />
        <RowDefinition Height="auto" />
    </Grid.RowDefinitions>

    <Grid Grid.Row="0">
        <Grid.LayoutTransform>
            <ScaleTransform ScaleX="{Binding ElementName=zoomer, Path=Value}" ScaleY="{Binding ElementName=zoomer, Path=Value}" x:Name="scaleTx" />
        </Grid.LayoutTransform>

        <Border Background="Aqua" BorderThickness="3" BorderBrush="Blue" Height="50" Width="50" />
    </Grid>
    <StackPanel Orientation="Horizontal" Grid.Row="1">
        <Slider x:Name="zoomer" Width="200" Value="1" Minimum="0.1" Maximum="3" TickFrequency="0.1" IsSnapToTickEnabled="True" Margin="3"/>
        <Button Content="Animate" Click="Button_Click" Margin="3"/>
    </StackPanel>
</Grid>

Code:

/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {

        //This represents the time it will take to zoom
        Duration zoomDuration = new Duration(TimeSpan.Parse("0:0:0.5"));

        //Set up animation for zooming
        DoubleAnimationUsingKeyFrames scaleAnimation = new DoubleAnimationUsingKeyFrames();
        scaleAnimation.Duration = zoomDuration;
        scaleAnimation.KeyFrames = GetAnimationSplines(zoomer.Maximum);

        scaleTx.BeginAnimation(ScaleTransform.ScaleXProperty, scaleAnimation);
        scaleTx.BeginAnimation(ScaleTransform.ScaleYProperty, scaleAnimation);
    }

    /// <summary>
    /// This creates a spline for zooming with non-linear acceleration patterns.
    /// </summary>
    /// <param name="moveTo"></param>
    /// <returns></returns>
    protected DoubleKeyFrameCollection GetAnimationSplines(double moveTo)
    {
        DoubleKeyFrameCollection returnCollection = new DoubleKeyFrameCollection();

        returnCollection.Add(new LinearDoubleKeyFrame(moveTo, KeyTime.FromPercent(1.0)));

        return returnCollection;
    }
}

The shape in the center of window will scale when slide is moved. Once you click animate button to apply animation, the zooming will animate but after that slider stops working.

I can corroborate that I've had this happen too, but I haven't yet found a clean solution. I had a case just like you describe in one of your answers - regarding the slider change not affecting the bound object after the animation has run (and yes, I had the FillBehavior set to Stop and/or run BeginAnimation(someProperty, null) to "release" the animation's "hold" on the property. To illustrate that I could still edit the property after animating (but not with the slider that was the source of the binding), I setup a button that would set the property to a specific value. This button did in fact work perfectly to change that property after the animation. It seems that in some cases WPF's binding may break as the result of certain animations.

A not-so-clean workaround might be to re-establish the binding in code in the animation's Completed handler.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top