原文:The VisualStateManager and Triggers

Author:Carole Snyder

  Silverlight 推出了可视化状态管理器( Visual State Manager ),它使得控件模版作者更方便地指定依赖可视化状态的控件外观。WPF Toolkit 附带了一个可视化状态管理器( Visual State Manager ),WPF 的下个版本将会加入 VSM。可以理解地,VisualStateManager 的引进带来了问题:何时使用 VSM 代替触发器,何时使用触发器会更适合。本博文尝试解决这个问题:更多对如何使用可视化状态管理器( VisualStateManager )的深入讨论在这里

  可视化状态管理器( VisualStateManager )支持 parts 和 states 模型,控件作者使可视化状态在控件模版中形式化的一种方法。可视化状态管理器( VisualStateManager )使控件作者能够管理一个控件的不同状态并且为设计工具提供了一个方法,比如 Microsoft Blend 支持通过控件的可视化状态自定义它的外观。在 parts 和 states 模型被引进之前,普遍地,当它改变了可视化状态,控件模版作者使用触发器来改变控件的外观。下面的控件模版中,当鼠标悬停在按钮上面或者按钮被按压时,使用触发器来改变按钮的 border 颜色。

<ControlTemplate TargetType="Button">
<Grid>
<Ellipse Fill="{TemplateBinding BorderBrush}"/>
<Ellipse x:Name="ButtonShape"
Margin="5"
Fill="{TemplateBinding Background}"/>
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Grid> <ControlTemplate.Triggers>
<Trigger Property="IsMouseOver"
Value="True">
<Setter Property="BorderBrush"
Value="Cyan"/>
</Trigger>
<Trigger Property="IsPressed"
Value="True">
<Setter Property="BorderBrush"
Value="Red"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>

  在这个模型中,没有关于什么是可视化状态正式的协议,这里只有定义在控件里的一些用来改变控件外观的属性。 A control that follows the parts and control model proactively communicates its visual states to control template authors.  当一个控件使用可视化状态管理器( VisualStateManager )来改变它的可视化状态,它就期望 控件模版(ControlTemplate )使用 可视化状态管理器( VisualStateManager )来为一个给定的可视化状态指定控件的外观。控件模版作者也可以通过可视化过渡(VisualTransitions)使用自定义可视化状态之间的过渡。可视化过渡(VisualTransitions)使得空间模版作者能够通过改变单个属性改变的时间和区间对单个过渡(transition)进行微调,甚至对在其他状态中没有提及的属性加上动画效果(animate)。下面的例子使用可视化状态管理器( VisualStateManager )而不是触发器来指定控件外观的改变。

<ControlTemplate TargetType="Button">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates"> <VisualStateGroup.Transitions>
<!--Take one half second to transition to the MouseOver state.-->
<VisualTransition To="MouseOver"
GeneratedDuration="0:0:0.5" />
</VisualStateGroup.Transitions> <VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver">
<Storyboard>
<ColorAnimation Duration="0"
Storyboard.TargetName="borderColor"
Storyboard.TargetProperty="Color"
To="Cyan"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<ColorAnimation Duration="0"
Storyboard.TargetName="borderColor"
Storyboard.TargetProperty="Color"
To="Red"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Ellipse>
<Ellipse.Fill>
<SolidColorBrush x:Name="borderColor"
Color="Black"/>
</Ellipse.Fill>
</Ellipse>
<Ellipse x:Name="ButtonShape"
Margin="5"
Fill="{TemplateBinding Background}"/>
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Grid>
</ControlTemplate>

  控件通过使用可视化状态管理器( VisualStateManager )并调用  VisualStateManager.GoToState 来改变可视化状态。当这一切发生时,在可视化状态(VisualState)和可视化过渡(VisualTransition)对象中, 可视化状态管理器( VisualStateManager )正确地停止和开始故事板(storyboards),因此按钮的外观正确地改变可视化状态。为此,这里有一个明确的分工:控件作者指定控件的哪个可视化状态并决定一个控件何时进入每一个可视化状态;模版作者指定这个控件在每个可视化状态中的外观。

  然而触发器在WPF中并不是没用了。你可以使用触发器改变控件的外观,这并不对应与一个可视化状态。举个例子,按钮有一个 IsDefault 属性,但是在按钮中没有一个相对应的可视化状态。控件模版作者可能想要指定依赖 IsDefault 的值的按钮外观,这是一个适合用触发器的情景。下面的例子重复了之前的例子,并加入了一个触发器来指定依赖 IsDefault 的值的按钮外观。

<ControlTemplate TargetType="Button">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates"> <VisualStateGroup.Transitions>
<!--Take one half second to transition to the MouseOver state.-->
<VisualTransition To="MouseOver"
GeneratedDuration="0:0:0.5" />
</VisualStateGroup.Transitions> <VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver">
<Storyboard>
<ColorAnimation Duration="0"
Storyboard.TargetName="borderColor"
Storyboard.TargetProperty="Color"
To="Cyan"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<ColorAnimation Duration="0"
Storyboard.TargetName="borderColor"
Storyboard.TargetProperty="Color"
To="Red"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Ellipse>
<Ellipse.Fill>
<SolidColorBrush x:Name="borderColor"
Color="Black"/>
</Ellipse.Fill>
</Ellipse>
<Ellipse x:Name="defaultOutline"
Stroke="{TemplateBinding Background}"
StrokeThickness="2"
Margin="2"/>
<Ellipse x:Name="ButtonShape"
Margin="5"
Fill="{TemplateBinding Background}"/>
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsDefault"
Value="False">
<Setter TargetName="defaultOutline"
Property="Stroke"
Value="Transparent"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>

  按钮中的 IsMouseOver 和 IsPressed 属性依然有效,但是你不应该创建触发器来阻止它们改变按钮的外观。这并不意味这些属性没有用了。这些属性依然可以被应用作者用来在代码中检查控件的可视化状态,甚至当他们使用可视化状态管理器(VisualStateManager)在它们的可视化状态之间过渡时,控件作者应该继续定义用于可视化状态的属性。

【翻译】VSM 和触发器的更多相关文章

  1. zabbix3.4.7触发器表达式详解

    zabbix触发器表达式详解 概述:触发器中的表达式使用很灵活,我们可以创建一个复杂的逻辑测试监控,触发器表达式形式如下: {<server>:<key>.<functi ...

  2. zabbix-3.4 触发器

    3 触发器 概述 触发器是"评估"由项目采集的数据并表示当前系统状况的逻辑表达式. 当监控项用于采集系统的数据时,始终遵循这些数据是非常不切合实际的,因为这些数据始终在等待一个令人 ...

  3. Bootstrap-17

    导入JavaScript插件: 一次性导入:Bootstrap提供了一个单一的文件,这个文件包含了Bootstrap的所有JavaScript插件,即bootstrap.js <!—导入jQue ...

  4. Blend 2015 教程 (四)控件模板

    前一篇讲述了修改ListBox样式的方法,本篇将修改性别显示区域的样式. 1. 选择ListBox控件,编辑ItemTemplate的当前项,选择CheckBox控件,在美工板导航栏中点击CheckB ...

  5. boostrap插件

    第一章:模态弹出框 一.导入JavaScript插件 Bootstrap的JavaScript插件可以单独导入到页面中,也可以一次性导入到页面中.因为在Bootstrap中的JavaScript插件都 ...

  6. Bootstrap模态弹出框

    前面的话 在 Bootstrap 框架中把模态弹出框统一称为 Modal.这种弹出框效果在大多数 Web 网站的交互中都可见.比如点击一个按钮弹出一个框,弹出的框可能是一段文件描述,也可能带有按钮操作 ...

  7. 自学Zabbix3.6.2-触发器triggers severity严重程度

    触发器严重性定义了触发器的重要性. 1. zabbix支持以下触发级别: SEVERITY DEFINITION 颜色 Not classified 未知. 灰色 Information 一般信息. ...

  8. Bootstrap支持的JavaScript插件

    1.导入JavaScript插件 Bootstrap除了包含丰富的Web组件之外,如前面介绍的下拉菜单.按钮组.导航.分页等.他还包括一些JavaScript的插件. Bootstrap的JavaSc ...

  9. HTML5物理游戏开发 - 越野山地自行车(三)粉碎自行车

    自上一章公布到如今已时隔四月,实在对不住大家.让大家久等了~话说不是我不关注我的博客,而是事情一多起来写博客的时间就少了. 待到今日有空了,回头看了看自己曾经写的文章,猛得发现已经四个月不曾写文章了. ...

随机推荐

  1. Android 学习之显式激活与隐式激活Activity

    在res界面里面有两个布局文件activity_main和acivity_two

  2. Python错误、调试和测试

    try: print('try...') r = 10 / int('a') print('result:', r) except ValueError as e: print('ValueError ...

  3. Java band [Cite]

    SampleModel  取样模型Databuffer 数据缓冲区 Raster 光栅Sample 样本band  带 SampleModel是java awt中的一个抽象类,它定义了一个接口,用于提 ...

  4. android: SQLite 数据库的最佳实践

    6.5.1    使用事务 前面我们已经知道,SQLite 数据库是支持事务的,事务的特性可以保证让某一系列的操 作要么全部完成,要么一个都不会完成.那么在什么情况下才需要使用事务呢?想象以下场 景, ...

  5. Top 20 Java Libries Used by Github's Most Popular Java Projects

    Top 20 Java Libries Used by Github's Most Popular Java Projects:

  6. 通过修改host文件来允许和禁止主机的访问

    通过修改host文件来允许和禁止主机的访问 修改/etc/hosts.deny,加入"sshd:ALL" 修改/etc/hosts.allow,加入"sshd:192.1 ...

  7. Adobe Illustrator里使用fontawesome矢量图标

     简单教程:1.安装FontAwesome.otf字体2.打开http://fontawesome.io/cheatsheet/3.选中图标图片,ctrl+c4.粘贴到AI中5.选中粘贴的内容,修改字 ...

  8. C# 汉字转拼音 使用微软的Visual Studio International Pack 类库提取汉字拼音首字母

    代码参考该文http://www.cnblogs.com/yazdao/archive/2011/06/04/2072488.html VS2015版本 1.使用Nuget 安装 "Simp ...

  9. Python 目录操作

    知道两个文件的绝对目录,怎样计算出两个文件的相对目录,例如:知道 a = '/usr/share/pyshared/test/a.py' b = '/usr/lib/dist/test/a.py' 可 ...

  10. IOS图像拉伸解决方案

    UIButton实现背景拉伸,即图片两端不拉伸中间拉伸的办法有如下两种: 第一种方法很简单而且使用性更广.做法就是直接拉伸想要setBackgroundImage的image,代码如下: UIImag ...