我已将Silverlight TemplatedControl移植到WPF,虽然它的行为基本相同,但动画不再有效。
当我致电VisualStateManager.GoToState()
时,它会返回false。为了手动强制执行此操作,我按照别人的建议,按名称查找了可视状态组,并强制运行故事板:
foreach (VisualStateGroup vsg in VisualStateManager.GetVisualStateGroups(part_LayoutRoot))
{
VisualState vs = vsg.States.Cast<VisualState>().FirstOrDefault(o => o.Name == visualState);
if (vs == null)
throw new ApplicationException("No visual state found with name: " + visualState);
vs.Storyboard.Begin();
break;
}
但是这会引发异常No applicable name scope exists to resolve the name 'PART_MyPart'
当我打电话给Storyboard.Begin()
时。
经过进一步调查,VisualStateManager,可视状态和故事板在调用NameScope.GetNameScope()
时都返回null,因此我尝试在代码中手动设置它们:
var nameScope = NameScope.GetNameScope(vs.Storyboard);
if (nameScope == null)
{
nameScope = NameScope.GetNameScope(part_LayoutRoot);
NameScope.SetNameScope(vsg, nameScope);
NameScope.SetNameScope(vs, nameScope);
NameScope.SetNameScope(vs.Storyboard, nameScope);
}
然而,异常继续被提升,我不能为我的生活思考为什么。这与Silverlight中的预期完全一样。
任何人都可以了解为什么Silverlight和WPF之间在NameScope方面会有不同的行为?
由于
答案 0 :(得分:1)
在控件模板中检索命名元素并调用storyboard.Begin(_retrievedElement)
而不是storyboard.Begin()
来解决“无适用名称范围”问题。在这种情况下,传递的框架元素的名称范围将应用于故事板。有关此方法的不同重载的详细信息,请参阅http://msdn.microsoft.com/en-us/library/system.windows.media.animation.storyboard.begin.aspx。
不幸的是,我无法重建Visual States Manager无法为您的控件工作的原因。
更新:我可能已经弄清楚为什么你的控件模板在Silverlight中工作,但在WPF中却没有。详情请见下一个答案。
答案 1 :(得分:0)
我也可能知道为什么你的移植控件模板不起作用:在WPF中,不可能在视觉状态下的故事板中使用绑定。请考虑以下模板:
<ControlTemplate x:Key="ButtonTemplate" TargetType="Button">
<Border x:Name="ButtonBorder" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="5" Background="White" BorderBrush="#FFB0B0B0">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0:0:0.3"/>
</VisualStateGroup.Transitions>
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver">
<Storyboard>
<ColorAnimation Storyboard.TargetName="rectangle" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"
To="{Binding (Border.BorderBrush).(SolidColorBrush.Color), ElementName=ButtonBorder}"
Duration="0"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed"/>
<VisualState x:Name="Disabled"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid>
<Rectangle x:Name="rectangle" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Fill="#00000000"/>
<ContentPresenter x:Name="ContentPresenter" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Grid>
</Border>
</ControlTemplate>
重要的部分是Visual State“MouseOver”,其中使用了元素绑定:此代码将在Silverlight中完美执行,而在WPF中数据绑定引擎将告诉您它找不到名为“ButtonBorder”的元素(查看“输出”窗口以跟踪数据绑定错误)。这与我在前面的回答中提到的命名空间问题有关。 解决此问题的方法如下:
<ControlTemplate x:Key="ButtonTemplate" TargetType="Button">
<Border x:Name="ButtonBorder" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="5" Background="White" BorderBrush="#FFB0B0B0">
<Border.Resources>
<Storyboard x:Key="MouseOverStoryboard">
<ColorAnimation Storyboard.TargetName="rectangle" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"
To="{Binding (Border.BorderBrush).(SolidColorBrush.Color), ElementName=ButtonBorder}"
Duration="0"/>
</Storyboard>
</Border.Resources>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0:0:0.3"/>
</VisualStateGroup.Transitions>
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver" Storyboard="{StaticResource MouseOverStoryboard}">
</VisualState>
<VisualState x:Name="Pressed"/>
<VisualState x:Name="Disabled"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid>
<Rectangle x:Name="rectangle" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Fill="#00000000"/>
<ContentPresenter x:Name="ContentPresenter" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Grid>
</Border>
</ControlTemplate>
现在,故事板被添加到根模板元素的Resource属性中,因此名称范围似乎适合。在可视状态下,只需使用静态资源标记扩展来引用故事板。请注意,此XAML不会在Silverlight中运行,因此您无法在两个项目中共享该文件。此外,Blend无法处理此标记,因此必须手动编写。
希望这有帮助。