none
DoubleAnimation.To的绑定问题,无法冻结此storyboard时间线树 RRS feed

  • 问题

  • 我编写了一个类继承自Grid,其中定义了一个RotateAngle属性,用于在类的外部更新旋转变换的角度,而且触发RotateAngleChanged路由事件。

        class PinPiece : Grid, INotifyPropertyChanged
        {
            private double rotateAngle;
            public double RotateAngle
            {
                get { return rotateAngle; }
                set
                {
                    rotateAngle = (value + 360) % 360;
                    double halfOfSpaceAngle = 10*pieceCount;
                    if (rotateAngle > halfOfSpaceAngle && rotateAngle < 180)
                    {
                        rotateAngle += 360 - 2*halfOfSpaceAngle;
                    }
                    else if (rotateAngle >= 180 && rotateAngle < 360 - halfOfSpaceAngle)
                    {
                        rotateAngle -= 360 - 2*halfOfSpaceAngle;
                    }
                    RaiseEvent(new RoutedEventArgs(PinPiece.RotateAngleChangedEvent));
                    OnPropertyChanged("RotateAngle");
                }
            }
            public static readonly RoutedEvent RotateAngleChangedEvent = EventManager.RegisterRoutedEvent(
                "RotateAngleChange",
                RoutingStrategy.Direct,
                typeof(RoutedEventHandler),
                typeof(PinPiece)
                );
            public event RoutedEventHandler RotateAngleChanged
            {
                add { AddHandler(RotateAngleChangedEvent, value); }
                remove { RemoveHandler(RotateAngleChangedEvent, value); }
            }
            private void OnPropertyChanged(string name)
            {
                PropertyChangedEventHandler hander = PropertyChanged;
                if (hander != null)
                {
                    hander(this, new PropertyChangedEventArgs(name));
                }
            }
        }

    我想在style中设置一个触发器,在RotateAngle发生变化时触发,旋转自身到RotateAngle所指定的角度。

        <Style x:Key="stylePinWheelPiece" TargetType="local:PinPiece">
            <Setter Property="Canvas.Top" Value="-66"/>
            <Setter Property="Width" Value="400"/>
            <Setter Property="Height" Value="133"/>
            <Setter Property="RenderTransform">
                <Setter.Value>
                    <RotateTransform CenterX="0" CenterY="66">
                    </RotateTransform>
                </Setter.Value>
            </Setter>
            <Style.Triggers>
                <EventTrigger RoutedEvent="RotateAngleChange">
                    <EventTrigger.Actions>
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimation Duration="0:0:0.3"
                                                 Storyboard.TargetProperty="(Grid.RenderTransform).(RotateTransform.Angle)"
                                                 >
                                    <DoubleAnimation.To>
                                        <Binding Path="RotateAngle">
                                            <Binding.RelativeSource>
                                                <RelativeSource Mode="FindAncestor" AncestorType="local:PinPiece"/>
                                            </Binding.RelativeSource>
                                        </Binding>
                                    </DoubleAnimation.To>
                                </DoubleAnimation>
                            </Storyboard>
                        </BeginStoryboard>
                    </EventTrigger.Actions>
                </EventTrigger>
            </Style.Triggers>
        </Style>

    运行时报错:

    未处理 System.Windows.Markup.XamlParseException
      ……(堆栈)
           Message=无法冻结此 Storyboard 时间线树供跨线程使用。
           Source=PresentationFramework

    经过排除,RotateAngleChanged事件工作良好,在我将DoubleAnimation.To设置为常数时正常运行。

    而绑定代码块在此情况下也能正常工作:

            <Setter Property="RenderTransform">
                <Setter.Value>
                    <RotateTransform CenterX="0" CenterY="66">
                        <RotateTransform.Angle>
                            <Binding Path="RotateAngle">
                                <Binding.RelativeSource>
                                    <RelativeSource Mode="FindAncestor" AncestorType="local:PinPiece"/>
                                </Binding.RelativeSource>
                            </Binding>
                        </RotateTransform.Angle>
                    </RotateTransform>
                </Setter.Value>
            </Setter>

    但当绑定部分添加到To属性中时就发生上述异常,经查,论坛中已有人做出过回答:

    http://social.msdn.microsoft.com/Forums/zh-CN/88fccc2d-bd7a-44f5-96aa-5d9c2ff19d43/-storyboard-?forum=wpfzhchs

    我的问题是,如何才能达到我的目的?(更改自定义类中RotateAngle属性,就能触发一个旋转变换的动画,此动画的目标值即为RotateAngle,能够将动画部分完全在Xaml中实现)

    我预期中可能可行的解决方法:

    1.有没有方法能够让To获得RotateAngle的瞬时值,而不用保持绑定?

    2.如何修改RotateAngle属性,使其能够被DoubleAnimation.To绑定?

    2014年7月28日 7:50

答案

  • 谢谢你的回复,我暂时也没发现能够达成我的目标的方法,只能在代码中进行相关的操作了。

    我发现Xaml能用于简化很多样式、动画、资源方面的代码,所以任何与这些相关的任务都想着交给Xaml完成,但实际上有些东西还是不得不动用代码。

    最后还是用了我非常不喜欢的DispatcherTimer,相比于用Storyboard果真是复杂了很多……

    2014年7月30日 8:15

全部回复

  • 你好,

    我认为不能达到这个效果。Animation的渲染在一条线程中,修改 RotateAngle 在另外一条线程中,两者无法通信。

    如果你有新的方式或者想法,欢迎与我交流。如果我理解错了也请指正。

    谢谢!


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    2014年7月29日 2:17
    版主
  • 谢谢你的回复,我暂时也没发现能够达成我的目标的方法,只能在代码中进行相关的操作了。

    我发现Xaml能用于简化很多样式、动画、资源方面的代码,所以任何与这些相关的任务都想着交给Xaml完成,但实际上有些东西还是不得不动用代码。

    最后还是用了我非常不喜欢的DispatcherTimer,相比于用Storyboard果真是复杂了很多……

    2014年7月30日 8:15