Go to visual states inside a Grid in code behind in Windows Store apps

限于喜欢 提交于 2019-11-29 16:16:32

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.

Typically I have a single UpdateVisualState(bool useTransitions) method in my controls that makes all the GoToVisualState() calls. If something can't be animated then I see two options:

  1. Make the change in code behind in my UpdateVisualState() method. The drawback of this solutions is that Blend will not show the change in the visual state editor. I don't personally care though because I rarely use Blend on already integrated designs and this solution is simple.
  2. Create a(n attached) property or behavior that makes the expected change and animate that property from the visual state Storyboard. That's a bit more work, but could keep Blend support in your project.
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!