WPF/Silverlight: VisualStateManager和Triggers有什么区别?

17

我发现可视化状态管理器和触发器之间存在某些功能重叠。

<VisualStateManager.VisualStateGroups>
   <VisualStateGroup x:Name="CommonStates">
      <VisualState x:Name="Pressed">
             ... bla bla ...
      </VisualState>
  </VisualStateGroup>
</VisualStateManager.VisualStateGroups>

或者我可以走

<Trigger Property="IsPressed" Value="true">
          ... bla bla ...
</Trigger>

我应该在什么情况下使用其中一个而不是另一个?


有一次,我添加了一个自定义的VisualState "NoItems"。如果使用触发器会更容易一些。 - vortexwolf
5个回答

13

为什么要使用VisualStateManager,而(不是最终)使用Triggers?

让我们从它们之间的一般区别开始。

  • 它们如何被触发:
    • 当一个属性更改了其时,触发器被触发。
    • 控件请求状态组中的状态时,VisualStates被触发。
  • 它们被触发时执行的操作:
    • 触发器:
      1. 通过Setter建立其他属性。
    • VisualState:
      1. VisualStateManager发起状态更改请求。
      2. VisualStateManager在设置状态之前执行VisualTransition
      3. VisualTransition执行Storyboard
      4. 当经过VisualTransitionGeneratedDuration指定的时间后,VisualStateManager会更新控件相应VisualStateGroupCurrentState属性。
      5. 接下来,VisualStateManager执行(1)中请求的初始VisualState
      6. 最后,VisualState执行另一个Storyboard

是的,你想得对,VisualStateManager使情景比Triggers更加复杂。然而,VisualStateManager的复杂性允许程序员做一些Triggers无法完成的事情(不是简单的方式):

  • 区分状态和状态转换之间的差异:
    • 在状态改变期间独立于状态本身生成动画,而不需要生成其他额外属性。
    • 通过正确设置VisualTransitionFromTo命令,可以允许重复使用同一转换。
    • 自动控制视觉问题和动画(例如在转换中停止转换动画并激活另一个动画)。
    • 易于添加/编辑/维护/删除复杂的动画,这有助于在复杂情况下进行编程。
  • 在触发VisualState时提供更大的灵活性:因为可以通过属性更改、事件、方法等方式进行触发。甚至(最神奇的是)不需要离开xaml,只需正确使用Behavior即可。

  • 同时实现多个状态和状态转换:因为可以将一组状态组分配给控件(VisualStateGroup),每个状态组在特定时间具有唯一的CurrentState。或许一张图片可以更好地说明: State-Based Navigation QuickStart Using the Prism Library 5.0 for WPF

  • 与WPF自然集成:由于控件隐式处理状态,并允许在控件的树形安排(父控件)中控制状态,这在WPF中自然发生。这使您可以仅用几行代码生成非常复杂的场景;当然,无需触碰控件的后台代码。

我相信还有更多优点。最有趣的是,如果您想使用Trigger自己实现这些优点,最终会陷入非常类似于VisualStateManager的系统中...试试吧!

但是...总是使用VisualStateManager并非好事

即使具有所有这些优点,也不应放弃Trigger系统而转向VisualStateManager系统。Trigger是一个更简单的系统,但它也有其潜力。

就我个人而言,对于不需要奇怪行为或动画效果的非常简单的“原始”控件,我会使用触发器。在这种类型的控件中,VisualStateManager 的实现复杂性不足以证明其使用。

对于更复杂的控件,尤其是那些使用其他“原始”控件的“复杂”控件(请注意“原始”和“复杂”概念的含义),我会使用 VisualStateManager。自然地,根据用户交互,这些控件具有复杂的行为。


9

这两者之间存在大量重叠。在处理复杂情况时,使用触发器可能会带来“痛苦”,因此稍后添加了 VisualStateManager 。总的来说,它更加灵活和易于使用。


7

有些事情用触发器做会更容易,而另一些则使用VSM(可视状态管理器)更简单。

使用VSM的最大原因是Silverlight不支持触发器。如果你希望将来转向Silverlight,请避免使用触发器。

VSM有两个缺点:

  • 你不能轻松地设置起始状态。最好的方法是在代码后台的某个位置进行设置,但这很麻烦。
  • 虽然在实现控件模板时经常需要,但不建议同时在两个不同状态组中对同一属性进行动画处理。你可以使用多个条件来获得触发器中状态重叠的更多细节。

然而,VSM似乎是未来的趋势。如果你正在使用Blend,那么配置VSM非常容易。


2
我认为您可以使用VisualStateManager(VSM)作为全局设计解决方案来创建控件契约,并在特定情况下将触发器作为视图元素的反应。
实现自定义控件并将其描述为“状态机”以及内部转换逻辑是一个好的实践。但是,触发器可以对周围控件或应用程序数据的更改做出反应。
我认为您可以在开发自定义控件时使用VisualStateManager,在开发具有多个控件的复杂视图时使用Triggers。
我不同意使用VSM的最大原因是Silverlight中不支持Triggers。您可以使用来自Blend SDK的Microsoft.Expression.Interaction+System.Windows.Interactivity中的Triggers。在Silverlight 5中,此功能将在silverlight核心中可用。

1
除了其他答案之外,使用视觉状态构建“设计”体验比使用触发器更容易。例如,Expression Blend 允许您交互式构建将在各种视觉状态下运行的故事板(Blend 3 的视频)。这是使用触发器难以轻松完成的。

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