3

我已将 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方面会有不同的行为吗?

谢谢

4

2 回答 2

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 中无效。下一个答案中的详细信息。

于 2013-04-19T16:45:47.710 回答
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>

重要的部分是使用元素绑定的视觉状态“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 无法处理此标记,因此必须手动编写。

希望这可以帮助。

于 2013-04-21T07:56:09.267 回答