Silverlight中的VisualStateManager:设置初始状态

时间:2012-03-01 17:34:51

标签: silverlight expression-blend visualstatemanager

我经常发现需要包含“离开”和“现在”类型的视觉状态,这些视觉状态用于根据某些其他条件为控件移动或显示设置动画。

然后,“离开”状态通常是应该是初始状态的状态。根据我的理解,没有办法在SL中定义初始状态,而是“base”,这根本不是一个状态,而是表示状态管理器尚未激活的状态(没有状态故事板运行到改变控件的外观。)

当然你可以设计“base”看起来像“离开”,但这意味着Expression Blend中的默认外观是不可见的(你不能永久地“固定”状态)。

要更改我尝试的初始状态

  • 在控件的ctor中设置状态,什么都不做,
  • 在ctor或Loaded事件的调度调用中设置状态,这两个事件都显示错误的状态为一瞬间。

所以问题似乎是无论视觉状态管理器做了什么,它都没有立即执行,但需要一个明显的瞬间来改变外观。

(直接为bootstrap设置属性当然是另一种选择,但只适用于UserControls:在模板化控件中,我必须引入另一个depprop模板绑定控件模板,这是我认为overkill开始的地方。 )

我想我已经覆盖了所有这些,我只能忍受一个看不见的基础状态?

我使用SL4。

1 个答案:

答案 0 :(得分:6)

我在Expression Blend中为WPF开发 UserControl 时遇到了类似的问题(注意:如果您正在开发自定义控件,请参阅下一节)。在那个UserControl中,我有一个我希望淡入的子元素,并作为叠加层存在。与您的情况一样,在我的工作流程中首先将覆盖元素设计为“完全成长和可见”状态,然后将其缩小并将其不透明度设置为“隐藏”状态。这样做,覆盖在Base状态下可见,但我需要UserControl的初始状态为隐藏状态。在这一点上,我有三个主要的相关状态:Base,“Hidden”和“Visible”(最后两个是State组的一部分)。

以下是我解决初始状态问题的方法。首先,我将GoToStateAction应用于由Loaded事件触发的根元素(到UserControl)。它告诉UserControl直接进入“隐藏”状态:

enter image description here

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

其次,我在状态组中为叠加层进行了适当的转换设置。可能有几种方法可以做到这一点,但这就是我如何做到的。首先,我将“默认转换”设置为令人满意的设置,比如说.4秒。接下来,我将从任何元素(Blend中的星形图标)到此“隐藏”状态的转换时间设置为0秒(这允许上述GoToStateAction设置“初始”状态,而用户不知道任何不同)。然后,我将从“可见”状态到“隐藏”状态的转换设置为适当的设置(比如.4秒)。基本上这涵盖了过渡的所有基础。关键是要确保从“任何元素”到“隐藏”状态的“转换”是立即的,然后在从叠加层的“可见”到“隐藏”状态的情况下覆盖那个立即转换。

enter image description here


设置 自定义控件的初始VisualState

如果您正在开发自定义控件(而不是UserControl)并因此在控件模板中定义VisualStateManager,则上述方法(基于Loaded事件启动VisualState更改)将可能不起作用。这是因为在调用OnApplyTemplate()覆盖之前,控件的可视树(在样式文件中定义)将被应用于您的控件,这通常是在第一个Loaded事件触发后。因此,如果您尝试启动VisualState更改以响应自定义控件的Loaded事件,则很可能不会发生任何事情。 相反,您需要在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);
    }
}