WPF动态创建故事板
WPF Create Storyboard Dynamically
我在 .net WPF 中动态创建的 UserControl 的 运行 情节提要有问题。
这些是我的例子 类:
class EventsPage {
// ...
public void AddEvent(Event @event) {
var eventUC = new EventUserContrl(@event);
eventUC.ExpandCollapseAnimation += ExpandCollapseAnimation;
EventsStackPanel.Children.Add(eventUC);
}
private ExpandCollapseAnimation(EventUserControl eventUC, double height, double time) {
// Create frames using custom functions for creating them.
var frames = new DoubleKeyFrameCollection() {
StoryBoardsBuilder.CreateEasingDoubleKeyFrame(0.0, eventUC.ActualHeight),
StoryBoardsBuilder.CreateEasingDoubleKeyFrame(time, destinationHeight)
};
// Create Animation.
var heightSizeAnimation= StoryBoardsBuilder.BuildDoubleAnimationUsingKeyFrames(
FillBehavior.Stop, frames, eventUC.Name, new PropertyPath("Height"));
// Create StoryBoard.
var storyboard = new Storyboard();
// Add Animations into StoryBoard.
storyboard.Children.Add(heightSizeAnimation);
// Create final function.
storyboard.Completed += (sender, e) => {
eventUC.Height = destinationHeight;
};
// Run animation.
storyboard.Begin(this);
}
// ...
}
启动后,在 storyboard.Begin(this)
处显示异常:
System.InvalidOperationException:
„Name „” cannot be found in the namespace „ProjectName.Pages.EventsPage ”.”
我做了类似的事情,但是为了在页面中手动放置用户控件,它可以工作,但这不会。
这是 StoryBuilder 代码:
public static EasingDoubleKeyFrame CreateEasingDoubleKeyFrame(
double frameTimeInSeconds,
double value) {
// Create double key frame.
return new EasingDoubleKeyFrame() {
KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(frameTimeInSeconds)),
Value = value
};
}
public static DoubleAnimationUsingKeyFrames BuildDoubleAnimationUsingKeyFrames(
FillBehavior fillBehavior,
DoubleKeyFrameCollection keyFrames,
string targetName,
PropertyPath targetProperty) {
// Create animation.
var animation = new DoubleAnimationUsingKeyFrames();
// Set animation end behavior.
animation.FillBehavior = fillBehavior;
// Set animation frames.
animation.KeyFrames = keyFrames;
// Set animation target object.
Storyboard.SetTargetName(animation, targetName);
// Set animation target property.
Storyboard.SetTargetProperty(animation, targetProperty);
return animation;
}
看来您 Storyboard
的目标设置有误。
Storyboard.SetTargetName
需要一个 registered 元素名称。
您有两个选择:使用 Storyboard.SetTarget
或注册控件的名称并使用 Storyboard.SetTargetName
.
解决方案 1:Storyboard.SetTarget
(推荐)
推荐的方法是在用 C# 创建动画时使用 Storyboard.SetTarget
(而不是更方便的 XAML)。 Storyboard.SetTargetName
需要 XAML 名称范围内的元素,使用 X:Name
指令设置 FrameworkElement.Name
。使用 Storyboard.SetTarget
消除了目标元素在名称范围内注册的要求。
StoryBoardBuilder.cs
class StoryBoardBuilder
{
public static DoubleAnimationUsingKeyFrames BuildDoubleAnimationUsingKeyFrames(
FillBehavior fillBehavior,
DoubleKeyFrameCollection keyFrames,
DependencyObject target,
PropertyPath targetProperty)
{
// Create animation.
var animation = new DoubleAnimationUsingKeyFrames();
// Set animation end behavior.
animation.FillBehavior = fillBehavior;
// Set animation frames.
animation.KeyFrames = keyFrames;
// Set animation target object.
Storyboard.SetTarget(animation, target);
// Set animation target property.
Storyboard.SetTargetProperty(animation, targetProperty);
return animation;
}
}
例子
class EventsPage
{
// ...
public void AddEvent(Event @event) {
var eventUC = new EventUserContrl(@event);
eventUC.ExpandCollapseAnimation += ExpandCollapseAnimation;
}
private ExpandCollapseAnimation(EventUserControl eventUC, double height, double time)
{
...
// Create Animation.
var heightSizeAnimation= StoryBoardBuilder.BuildDoubleAnimationUsingKeyFrames(
FillBehavior.Stop,
frames,
eventUC,
new PropertyPath("Height"));
...
}
// ...
}
解决方案 2:Storyboard.SetTargetName
Storyboard.SetTargetName
需要一个名为 FrameworkElement
的动画目标。此元素的名称必须在当前 XAML 名称范围内注册。这是在使用 x:Name
指令命名 XAML 中的元素时自动完成的。
由于您决定在 C# 中创建元素,因此您必须手动注册元素名称。如果没有活动的名称范围,您还必须手动创建一个新的名称范围。
访问现有名称范围的最简单方法是引用命名的 XAML 元素。在这个元素上,您调用 FrameworkElement.RegisterName
来注册一个元素。请参阅 Microsoft Docs: Targeting Framework Elements, Framework Content Elements, and Freezables 以了解更多信息。
StoryBoardBuilder.cs
class StoryBoardBuilder
{
public static DoubleAnimationUsingKeyFrames BuildDoubleAnimationUsingKeyFrames(
FillBehavior fillBehavior,
DoubleKeyFrameCollection keyFrames,
string targetName,
PropertyPath targetProperty)
{
// Create animation.
var animation = new DoubleAnimationUsingKeyFrames();
// Set animation end behavior.
animation.FillBehavior = fillBehavior;
// Set animation frames.
animation.KeyFrames = keyFrames;
// Set animation target object.
Storyboard.SetTargetName(animation, targetName);
// Set animation target property.
Storyboard.SetTargetProperty(animation, targetProperty);
return animation;
}
}
例子
class EventsPage
{
// ...
public void AddEvent(Event @event)
{
var eventUC = new EventUserContrl(@event);
// Name the element
eventUC.Name = "MyEventUserContrl";
// Register the element name in the current name scope manually
// using an existing named element
EventsStackPanel.RegisterName(eventUC.Name, eventUC);
EventsStackPanel.Children.Add(eventUC);
eventUC.ExpandCollapseAnimation += ExpandCollapseAnimation;
}
private ExpandCollapseAnimation(EventUserControl eventUC, double height, double time)
{
...
// Create Animation.
var heightSizeAnimation= StoryBoardBuilder.BuildDoubleAnimationUsingKeyFrames(
FillBehavior.Stop,
frames,
eventUC.Name,
new PropertyPath("Height"));
...
}
// ...
}
我在 .net WPF 中动态创建的 UserControl 的 运行 情节提要有问题。
这些是我的例子 类:
class EventsPage {
// ...
public void AddEvent(Event @event) {
var eventUC = new EventUserContrl(@event);
eventUC.ExpandCollapseAnimation += ExpandCollapseAnimation;
EventsStackPanel.Children.Add(eventUC);
}
private ExpandCollapseAnimation(EventUserControl eventUC, double height, double time) {
// Create frames using custom functions for creating them.
var frames = new DoubleKeyFrameCollection() {
StoryBoardsBuilder.CreateEasingDoubleKeyFrame(0.0, eventUC.ActualHeight),
StoryBoardsBuilder.CreateEasingDoubleKeyFrame(time, destinationHeight)
};
// Create Animation.
var heightSizeAnimation= StoryBoardsBuilder.BuildDoubleAnimationUsingKeyFrames(
FillBehavior.Stop, frames, eventUC.Name, new PropertyPath("Height"));
// Create StoryBoard.
var storyboard = new Storyboard();
// Add Animations into StoryBoard.
storyboard.Children.Add(heightSizeAnimation);
// Create final function.
storyboard.Completed += (sender, e) => {
eventUC.Height = destinationHeight;
};
// Run animation.
storyboard.Begin(this);
}
// ...
}
启动后,在 storyboard.Begin(this)
处显示异常:
System.InvalidOperationException:
„Name „” cannot be found in the namespace „ProjectName.Pages.EventsPage ”.”
我做了类似的事情,但是为了在页面中手动放置用户控件,它可以工作,但这不会。
这是 StoryBuilder 代码:
public static EasingDoubleKeyFrame CreateEasingDoubleKeyFrame(
double frameTimeInSeconds,
double value) {
// Create double key frame.
return new EasingDoubleKeyFrame() {
KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(frameTimeInSeconds)),
Value = value
};
}
public static DoubleAnimationUsingKeyFrames BuildDoubleAnimationUsingKeyFrames(
FillBehavior fillBehavior,
DoubleKeyFrameCollection keyFrames,
string targetName,
PropertyPath targetProperty) {
// Create animation.
var animation = new DoubleAnimationUsingKeyFrames();
// Set animation end behavior.
animation.FillBehavior = fillBehavior;
// Set animation frames.
animation.KeyFrames = keyFrames;
// Set animation target object.
Storyboard.SetTargetName(animation, targetName);
// Set animation target property.
Storyboard.SetTargetProperty(animation, targetProperty);
return animation;
}
看来您 Storyboard
的目标设置有误。
Storyboard.SetTargetName
需要一个 registered 元素名称。
您有两个选择:使用 Storyboard.SetTarget
或注册控件的名称并使用 Storyboard.SetTargetName
.
解决方案 1:Storyboard.SetTarget
(推荐)
推荐的方法是在用 C# 创建动画时使用 Storyboard.SetTarget
(而不是更方便的 XAML)。 Storyboard.SetTargetName
需要 XAML 名称范围内的元素,使用 X:Name
指令设置 FrameworkElement.Name
。使用 Storyboard.SetTarget
消除了目标元素在名称范围内注册的要求。
StoryBoardBuilder.cs
class StoryBoardBuilder
{
public static DoubleAnimationUsingKeyFrames BuildDoubleAnimationUsingKeyFrames(
FillBehavior fillBehavior,
DoubleKeyFrameCollection keyFrames,
DependencyObject target,
PropertyPath targetProperty)
{
// Create animation.
var animation = new DoubleAnimationUsingKeyFrames();
// Set animation end behavior.
animation.FillBehavior = fillBehavior;
// Set animation frames.
animation.KeyFrames = keyFrames;
// Set animation target object.
Storyboard.SetTarget(animation, target);
// Set animation target property.
Storyboard.SetTargetProperty(animation, targetProperty);
return animation;
}
}
例子
class EventsPage
{
// ...
public void AddEvent(Event @event) {
var eventUC = new EventUserContrl(@event);
eventUC.ExpandCollapseAnimation += ExpandCollapseAnimation;
}
private ExpandCollapseAnimation(EventUserControl eventUC, double height, double time)
{
...
// Create Animation.
var heightSizeAnimation= StoryBoardBuilder.BuildDoubleAnimationUsingKeyFrames(
FillBehavior.Stop,
frames,
eventUC,
new PropertyPath("Height"));
...
}
// ...
}
解决方案 2:Storyboard.SetTargetName
Storyboard.SetTargetName
需要一个名为 FrameworkElement
的动画目标。此元素的名称必须在当前 XAML 名称范围内注册。这是在使用 x:Name
指令命名 XAML 中的元素时自动完成的。
由于您决定在 C# 中创建元素,因此您必须手动注册元素名称。如果没有活动的名称范围,您还必须手动创建一个新的名称范围。
访问现有名称范围的最简单方法是引用命名的 XAML 元素。在这个元素上,您调用 FrameworkElement.RegisterName
来注册一个元素。请参阅 Microsoft Docs: Targeting Framework Elements, Framework Content Elements, and Freezables 以了解更多信息。
StoryBoardBuilder.cs
class StoryBoardBuilder
{
public static DoubleAnimationUsingKeyFrames BuildDoubleAnimationUsingKeyFrames(
FillBehavior fillBehavior,
DoubleKeyFrameCollection keyFrames,
string targetName,
PropertyPath targetProperty)
{
// Create animation.
var animation = new DoubleAnimationUsingKeyFrames();
// Set animation end behavior.
animation.FillBehavior = fillBehavior;
// Set animation frames.
animation.KeyFrames = keyFrames;
// Set animation target object.
Storyboard.SetTargetName(animation, targetName);
// Set animation target property.
Storyboard.SetTargetProperty(animation, targetProperty);
return animation;
}
}
例子
class EventsPage
{
// ...
public void AddEvent(Event @event)
{
var eventUC = new EventUserContrl(@event);
// Name the element
eventUC.Name = "MyEventUserContrl";
// Register the element name in the current name scope manually
// using an existing named element
EventsStackPanel.RegisterName(eventUC.Name, eventUC);
EventsStackPanel.Children.Add(eventUC);
eventUC.ExpandCollapseAnimation += ExpandCollapseAnimation;
}
private ExpandCollapseAnimation(EventUserControl eventUC, double height, double time)
{
...
// Create Animation.
var heightSizeAnimation= StoryBoardBuilder.BuildDoubleAnimationUsingKeyFrames(
FillBehavior.Stop,
frames,
eventUC.Name,
new PropertyPath("Height"));
...
}
// ...
}