在 Windows 应用商店应用程序的代码中转到网格内的视觉状态转到、网格、应用程序、商店

2023-09-07 08:42:23 作者:把回忆锁好

So my xaml code looks like this -

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

I can't use the GoToVisualState behavior because I need to do some checks before running this animation. So I guess I will have to call something like GoToState or GoToElementState in code behind.

耗时7月 微软Windows 8 应用总数破10万

However, ExtendedVisualStateManager doesn't seem to exist in WinRT. I tried using

VisualStateManager.GetCustomVisualStateManager(this.LayoutRoot)

but it always returns null.

Is there any workaround for this?

解决方案

Just figured this out.

First create a helper class just like how we used to use it in Silverlight or Windows Phone (I took this piece of code from here and modified it a little bit so when an element doesn't have any visual state groups attached, it automatically goes search for its parent until it finds any).

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;
    }
}

Then you will need to manually update the xaml to something like this -

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

I guess the good thing about this solution is that you can still see the visual states in Blend's States tab, for Blend lovers this is just cool.