我有一个WPF画布,我正在从代码中动态创建对象。通过设置RenderTransform属性来转换这些对象,并且需要在其中一个转换中应用动画。目前,我无法将任何变换的属性设置为动画(虽然不会引发异常并且动画似乎运行 - 已完成的事件被引发)。
此外,如果动画系统受到压力,有时也不会引发Storyboard.Completed事件。
我所有的例子都是来自XAML的转换动画。 MSDN documentation建议必须设置变换的x:Name属性才能使其可动画,但我还没有找到一种从代码中设置它的工作方式。
有什么想法吗?
以下是重现问题的完整代码清单:
using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace AnimationCompletedTest {
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window {
Canvas panel;
public MainWindow() {
InitializeComponent();
MouseDown += DoDynamicAnimation;
Content = panel = new Canvas();
}
void DoDynamicAnimation(object sender, MouseButtonEventArgs args) {
for (int i = 0; i < 12; ++i) {
var e = new Ellipse {
Width = 16,
Height = 16,
Fill = SystemColors.HighlightBrush
};
Canvas.SetLeft(e, Mouse.GetPosition(this).X);
Canvas.SetTop(e, Mouse.GetPosition(this).Y);
var tg = new TransformGroup();
var translation = new TranslateTransform(30, 0);
tg.Children.Add(translation);
tg.Children.Add(new RotateTransform(i * 30));
e.RenderTransform = tg;
panel.Children.Add(e);
var s = new Storyboard();
Storyboard.SetTarget(s, translation);
Storyboard.SetTargetProperty(s, new PropertyPath(TranslateTransform.XProperty));
s.Children.Add(
new DoubleAnimation(3, 100, new Duration(new TimeSpan(0, 0, 0, 1, 0))) {
EasingFunction = new PowerEase {EasingMode = EasingMode.EaseOut}
});
s.Completed +=
(sndr, evtArgs) => {
Debug.WriteLine("Animation {0} completed {1}", s.GetHashCode(), Stopwatch.GetTimestamp());
panel.Children.Remove(e);
};
Debug.WriteLine("Animation {0} started {1}", s.GetHashCode(), Stopwatch.GetTimestamp());
s.Begin();
}
}
[STAThread]
public static void Main() {
var app = new Application();
app.Run(new MainWindow());
}
}
}
答案 0 :(得分:24)
忽略故事板:
var T = new TranslateTransform(40, 0);
Duration duration = new Duration(new TimeSpan(0, 0, 0, 1, 0));
DoubleAnimation anim = new DoubleAnimation(30, duration);
T.BeginAnimation(TranslateTransform.YProperty, anim);
(语法的小修复)
答案 1 :(得分:12)
似乎在谷歌搜索后我自己解决了这个问题。非常感谢MSDN documentation和a post in MSDN forums by Antares19。
总结:
对于可由Storyboard定位的Freezable对象(如TranslateTransform),它必须具有注册名称。这可以通过调用FrameworkElement.RegisterName(..)。
我将Storyboard对象添加到我注册TranslateTransform的同一Framework元素的ResourceDictionary。这可以通过调用ResourceDictionary.Add(..)
这是更新的代码,现在可以很好地动画,并注册/注销添加的资源:
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace AnimationCompletedTest {
public partial class MainWindow : Window {
Canvas panel;
public MainWindow() {
InitializeComponent();
MouseDown += DoDynamicAnimation;
Content = panel = new Canvas();
}
void DoDynamicAnimation(object sender, MouseButtonEventArgs args) {
for (int i = 0; i < 12; ++i) {
var e = new Ellipse { Width = 16, Height = 16, Fill = SystemColors.HighlightBrush };
Canvas.SetLeft(e, Mouse.GetPosition(this).X);
Canvas.SetTop(e, Mouse.GetPosition(this).Y);
var tg = new TransformGroup();
var translation = new TranslateTransform(30, 0);
var translationName = "myTranslation" + translation.GetHashCode();
RegisterName(translationName, translation);
tg.Children.Add(translation);
tg.Children.Add(new RotateTransform(i * 30));
e.RenderTransform = tg;
panel.Children.Add(e);
var anim = new DoubleAnimation(3, 100, new Duration(new TimeSpan(0, 0, 0, 1, 0))) {
EasingFunction = new PowerEase { EasingMode = EasingMode.EaseOut }
};
var s = new Storyboard();
Storyboard.SetTargetName(s, translationName);
Storyboard.SetTargetProperty(s, new PropertyPath(TranslateTransform.YProperty));
var storyboardName = "s" + s.GetHashCode();
Resources.Add(storyboardName, s);
s.Children.Add(anim);
s.Completed +=
(sndr, evtArgs) => {
panel.Children.Remove(e);
Resources.Remove(storyboardName);
UnregisterName(translationName);
};
s.Begin();
}
}
[STAThread]
public static void Main() {
var app = new Application();
app.Run(new MainWindow());
}
}
}
答案 2 :(得分:3)
我有一个使用XAML / C#Combo的解决方案。在您的XAML文件中定义:
<UserControl.RenderTransform>
<TranslateTransform x:Name="panelTrans" Y="0"></TranslateTransform>
</UserControl.RenderTransform>
这将使您能够在C#代码中执行以下操作:
Storyboard.SetTargetName(mFlyInDA, "panelTrans");
Storyboard.SetTargetProperty(mFlyInDA, new PropertyPath("Y"));
其余的照常营业。创建DoubleAnimation,设置其属性,将其作为子项添加到Storyboard,在故事板上调用Begin函数。
答案 3 :(得分:0)
如果目标是要设置动画的FrameworkElement,则无需注册转换或将情节提要添加到资源集合中。您可以使用Blend生成PropertyPath语法。
frameworkElement.RenderTransform = new TransformGroup
{
Children =
{
new ScaleTransform(),
new SkewTransform(),
new RotateTransform(),
translate
}
};
translate.X = 100.0;
var animation = new DoubleAnimation(0.0, TimeSpan.FromSeconds(1));
var sb = new Storyboard();
sb.Children.Add(animation);
Storyboard.SetTarget(animation, frameworkElement);
Storyboard.SetTargetProperty(animation, new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)"));
sb.Begin();