ScaleX上的LayoutTransform动画和ScaleY打破了它们的绑定

时间:2012-03-26 07:27:16

标签: wpf data-binding animation scaletransform layouttransform

我有一个自定义类说'MyCanvas'派生自wpf Canvas类。 MyCanvas有一个依赖属性'Scale',它指定画布的缩放变换。现在,当Scale的值发生变化时,我想要将变换从旧值设置为新值。因为我正在使用LayoutTransform.BeginAnimation(...)方法。

代码:

//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>

但是在执行此代码后,ScaleXScaleYScale(viewmodel中的属性)的绑定正在破坏,即更改Scale的值不会改变比例在画布上。

错误消息(使用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')

如果有人解决此问题,请告诉我。感谢

3 个答案:

答案 0 :(得分:0)

这不是上述问题的解决方案,而是一个重现上述问题的工作样本WPF Application

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>

代码:

/// <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.

答案 1 :(得分:0)

好吧,今天我尝试了一些事情,突然间问题得到了解决。我不明白它是如何开始工作的。我对代码进行了以下更改,我之前也尝试过。

scaleAnimation.FillBehavior = FillBehavior.Stop;

任何人都可以向我解释这个。感谢。

答案 2 :(得分:0)

我可以证实我也曾经发生这种情况,但我还没有找到一个干净的解决方案。我有一个案例,就像你在一个答案中描述的那样 - 关于在动画运行后滑块更改不影响绑定对象(是的,我将FillBehavior设置为Stop和/或运行BeginAnimation(someProperty, null)以“释放”动画在属性上的“保持”。为了说明我仍然可以在动画后编辑属性(但不是使用作为绑定源的滑块),我设置了一个按钮,将该属性设置为一个特定的值。这个按钮实际上完全可以在动画后改变该属性。似乎在某些情况下,WPF的绑定可能会因某些动画而中断。

一个不那么干净的解决方法可能是在动画的Completed处理程序中的代码中重新建立绑定。