在Windows应用商店应用中的代码中转到网格内的可视状态

时间:2014-05-16 14:02:19

标签: windows-8 windows-runtime windows-store-apps winrt-xaml windows-8.1

所以我的xaml代码看起来像这样 -

<Grid x:Name="LayoutRoot">
    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup x:Name="CommonStates">

我无法使用GoToVisualState行为,因为我需要在运行此动画之前进行一些检查。所以我想我必须在后面的代码中调用类似GoToStateGoToElementState的内容。

但是, WinRT 中似乎不存在ExtendedVisualStateManager。我尝试使用

VisualStateManager.GetCustomVisualStateManager(this.LayoutRoot)

但它始终返回null

有没有解决方法呢?

2 个答案:

答案 0 :(得分:3)

刚想出来。

首先创建一个帮助程序类,就像我们以前在Silverlight或Windows Phone中使用它一样(我从here获取了这段代码并对其进行了一些修改,以便当一个元素没有任何视觉效果时状态组附加,它会自动搜索其父级,直到它找到任何)。

public class ExtendedVisualStateManager : VisualStateManager
{
    protected override bool GoToStateCore(Control control, FrameworkElement stateGroupsRoot, string stateName, VisualStateGroup group, VisualState state, bool useTransitions)
    {
        if ((group == null) || (state == null))
        {
            return false;
        }

        if (control == null)
        {
            control = new ContentControl();
        }

        return base.GoToStateCore(control, stateGroupsRoot, stateName, group, state, useTransitions);
    }

    public static bool GoToElementState(FrameworkElement element, string stateName, bool useTransitions)
    {
        var root = FindNearestStatefulFrameworkElement(element);

        var customVisualStateManager = VisualStateManager.GetCustomVisualStateManager(root) as ExtendedVisualStateManager;

        return ((customVisualStateManager != null) && customVisualStateManager.GoToStateInternal(root, stateName, useTransitions));
    }

    private static FrameworkElement FindNearestStatefulFrameworkElement(FrameworkElement element)
    {
        while (element != null && VisualStateManager.GetCustomVisualStateManager(element) == null)
        {
            element = element.Parent as FrameworkElement;
        }

        return element;
    }

    private bool GoToStateInternal(FrameworkElement stateGroupsRoot, string stateName, bool useTransitions)
    {
        VisualStateGroup group;
        VisualState state;

        return (TryGetState(stateGroupsRoot, stateName, out group, out state) && this.GoToStateCore(null, stateGroupsRoot, stateName, group, state, useTransitions));
    }

    private static bool TryGetState(FrameworkElement element, string stateName, out VisualStateGroup group, out VisualState state)
    {
        group = null;
        state = null;

        foreach (VisualStateGroup group2 in VisualStateManager.GetVisualStateGroups(element))
        {
            foreach (VisualState state2 in group2.States)
            {
                if (state2.Name == stateName)
                {
                    group = group2;
                    state = state2;
                    return true;
                }
            }
        }

        return false;
    }
}

然后你需要手动将xaml更新为这样的东西 -

<VisualStateManager.CustomVisualStateManager>
    <common:ExtendedVisualStateManager />
</VisualStateManager.CustomVisualStateManager>
<VisualStateManager.VisualStateGroups>
    <VisualStateGroup .../>
</VisualStateManager.VisualStateGroups>

我想这个解决方案的好处在于你仍然可以在Blend的状态标签中看到视觉状态,对于Blend爱好者来说这很酷。

答案 1 :(得分:0)

通常,我的控件中有一个UpdateVisualState(bool useTransitions)方法可以进行所有GoToVisualState()次调用。如果某些内容无法动画,那么我会看到两个选项:

  1. 在我的UpdateVisualState()方法中修改代码。此解决方案的缺点是Blend不会在可视状态编辑器中显示更改。我个人并不在乎,因为我很少在已经集成的设计上使用Blend,这个解决方案很简单。
  2. 创建一个(n附加的)属性或行为,该属性或行为会产生预期的更改,并从可视状态Storyboard为该属性设置动画。这是一项更多的工作,但可以在您的项目中保持Blend支持。