【问题标题】:Go to visual states inside a Grid in code behind in Windows Store apps在 Windows 应用商店应用程序的代码中转到网格内的视觉状态
【发布时间】:2014-07-05 00:29:08
【问题描述】:

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

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

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

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

VisualStateManager.GetCustomVisualStateManager(this.LayoutRoot)

但它总是返回null

有什么解决方法吗?

【问题讨论】:

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


    【解决方案1】:

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

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

    【讨论】:

    • 如果包含视觉状态的元素是Control的类型,则第一种方法将起作用;如果它是Grid 或不继承自Control 的东西,则需要使用ExtendedVisualStateManager 或类似的东西。第二种方法可行,但你会失去视觉状态之间的所有转换。
    • 不是真的,如果你使用这两种方法中的任何一种——你基本上是在编写代码,所以你可以在其中做任何你想做的事情——运行故事板动画、每帧动画甚至动画非动画属性,如Grid.ColumnDefinitions
    • 是的,任何事情都可以通过代码完成,但在这种情况下,这两种解决方案都不理想,因为您最终会编写大量额外的代码,这些代码可以在视觉状态管理器中自动生成。例如,您永远不需要编写故事板来从特定状态返回正常状态。 VisualStateManager 为你做这件事。
    • 我不是说不要使用 VSM,我的意思是你可以同时使用两者,尽管 CustomVisualStateManager 确实听起来是最好的解决方案。
    • 这对我在 WinRT 上不起作用。我复制了扩展的 vsm 并按照建议的答案更新了 XAML。但是,不会发生更新。具体来说,我使用的是网格控件。我使用以下调用:ExtendedVisualStateManager.GoToElementState(grid, "InitializedState", useTransitions: true);
    【解决方案2】:

    刚刚想通了。

    首先创建一个帮助类,就像我们过去在 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 的 States 选项卡中看到 视觉状态,对于 Blend 爱好者来说,这真是太酷了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多