Silverlight中的VisualStateManager:设置初始状态

5

我经常需要包含“离开”和“出现”类型的视觉状态,这些状态用于根据某些其他条件对控件进行动画处理。

然后,“离开”状态通常应该是初始状态。据我所知,在SL中没有办法定义一个初始状态,只有“基础”状态,它实际上并不是一个状态,而是表示状态管理器尚未激活(没有状态故事板在运行以改变控件的外观)。

当然,您可以将“基础”设计成看起来像“离开”,但这意味着在Expression Blend中默认外观是不可见的(您也无法永久“固定”状态)。

为了更改初始状态,我尝试过:

  • 在控件的构造函数中设置状态,但没有任何作用;
  • 在构造函数或Loaded事件的调度调用中设置状态,两者都会短暂地显示错误状态。

因此,问题似乎是无论视觉状态管理器做什么,它都不会立即完成,而需要一个明显的短暂时间来改变外观。

(直接为引导设置属性是另一个选项,但仅适用于UserControls:在模板化控件中,我必须引入另一个depprop来将控件模板与之绑定,这是我认为过度的地方。)

我想我已经涵盖了所有内容,只能接受看不见基础状态了吗?

我使用SL4。


不确定你在这里具体在问什么,约翰。你不能只将你的基本状态设置为“离开”,然后使用一些GoToStateAction来设置由你的条件触发的状态吗?不确定为什么你必须有一个无意中不可见的默认“Base”状态?你可以看看默认按钮控件模板如何使用“Normal”状态。 - Chris W.
@Chris 如果我的基本状态是“离开”,那么在设计控件时我看不到任何东西。默认按钮是不同的-它们在其“正常”状态下不是不可见的。 - John
1个回答

6
在使用Expression Blend为WPF开发UserControl时,我遇到了类似的问题(注意:如果您正在开发自定义控件,请参见我的下一节)。在那个UserControl中,我有一个子元素,希望它作为覆盖层淡入并逐渐变大。与您的情况类似,按照我的工作流程,在其“完全生长和可见”的状态下首先设计遮罩层元素,然后将其缩小并设置其不透明度为“隐藏”状态是有意义的。这样做,覆盖层在Base状态下是可见的,但我需要UserControl的初始状态是Hidden状态。此时,我有三个主要相关状态:Base,“Hidden”和“Visible”(这后两个是状态组的一部分)。 以下是我如何解决初始状态问题的方法。首先,我在根元素(即UserControl)上应用了GoToStateAction,该动作由Loaded事件触发。它告诉UserControl直接进入“Hidden”状态:

enter image description here

<i:Interaction.Triggers>
  <i:EventTrigger>
    <ei:GoToStateAction TargetObject="{Binding ElementName=userControl}" StateName="Hidden"/>
  </i:EventTrigger>
</i:Interaction.Triggers>

其次,我在叠加层的状态组中设置了适当的过渡设置。可能有几种方法可以做到这一点,但以下是我所做的。首先,我将“默认过渡”设置为令人满意的设置,比如0.4秒。接下来,我将从任何元素(在Blend中的星形图标)到此“隐藏”状态的过渡时间设置为0秒(这允许上述GoToStateAction设置“初始”状态而不使用户知道任何不同)。然后,我将从“可见”状态到“隐藏”状态的过渡设置为适当的设置(比如0.4秒)。基本上,这涵盖了所有过渡的情况。关键是确保从“任何元素”到“隐藏”状态的“过渡”是立即的,然后在从叠加层的“可见”到“隐藏”状态的情况下覆盖该立即过渡。
设置自定义控件的初始视觉状态:如果您正在开发自定义控件(而不是UserControl),因此在控件模板中定义VisualStateManager,则上述方法(根据Loaded事件启动VisualState更改)可能无法正常工作。这是因为您控件的可视树(在样式文件中定义)会在OnApplyTemplate()重写被调用之前应用于您的控件,通常是在第一个Loaded事件触发之后。因此,如果您尝试在自定义控件的Loaded事件响应中启动VisualState更改,则很可能什么也不会发生。相反,您需要在OnApplyTemplate()重写代码中启动状态更改。
public class MyCustomControl : ContentControl
{
    // ... other code ....


    public MyCustomControl()
    {
        // avoid designer errors
        if (DesignerProperties.GetIsInDesignMode(this))
            return;

        Loaded += new RoutedEventHandlerMyCustomControl_Loaded);
    }

    // This probably won't be called until AFTER OnApplyTemplate() gets
    //  called, so don't expect for your control to even have a visual tree
    //  yet when your control is first being contructed at runtime.
    private void MyCustomControl_Loaded(object sender, RoutedEventArgs e)
    {

    }

    public override void OnApplyTemplate()
    {
        // Avoid Visual Studio 2010 designer exceptions
        // (Visual Studio can't handle the VisualState change at design-time)
        if (DesignerProperties.GetIsInDesignMode(this))
            return;

        base.OnApplyTemplate();

        // Now we know that the template has been applied, we have a visual tree,
        //  so state changes will work
        VisualStateManager.GoToState(this, "MyInitialState", false);
    }
}

谢谢。你帮我省了很多麻烦! - Pitarou
太棒了!这很聪明,运行良好,而且还可以解决其他问题。 - Alan McBee
嘿,你应该点击“接受”按钮,因为Jason回答你的问题做得非常好 :) 我想你忘了! - Rachael

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接