原文: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. 指定的参数错误。Vim.Host.DiskPartitionInfo.-spec VSPHERE.LOCAL\Administrator WIN-DOPGQVRRU2C

    ESXI5.5 工作需要,最近在研究虚拟化的东西. 项目做分布式开发需要很多开发服务器,公司没钱只好拿一台之前使用的Dell的服务器做虚拟机.质询了一下公司IT部门,他们使用的是vmware的一套方案 ...

  2. 分析Linux内核中进程的调度(时间片轮转)-《Linux内核分析》Week2作业

    1.环境的搭建: 这个可以参考孟宁老师的github:mykernel,这里不再进行赘述.主要是就是下载Linux3.9的代码,然后安装孟宁老师编写的patch,最后进行编译. 2.代码的解读 课上的 ...

  3. SpringCloud+Consul 服务注册与服务发现

    SpringCloud+Consul 服务注册与服务发现 1. 服务注册: 在Spring.factories有一段: # Discovery Client Configuration org.spr ...

  4. hdu 1548 楼梯 bfs或最短路 dijkstra

    http://acm.hdu.edu.cn/showproblem.php?pid=1548 Online Judge Online Exercise Online Teaching Online C ...

  5. 分页sql语句优化

    MySQL的limit工作原理就是先读取n条记录,然后抛弃前n条,读m条想要的,所以n越大,性能会越差. 一般的分页做法,测试耗时 10.961s   SELECT * FROM v_history_ ...

  6. linux中touch命令参数修改文件的时间戳(转)

    linux中touch命令参数不常用,一般在使用make的时候可能会用到,用来修改文件时间戳,或者新建一个不存在的文件,以下是linux中touch命令参数的使用方法: touch [-acm][-r ...

  7. Android UI系列-----时间、日期、Toasts和进度条Dialog

    您可以通过点击 右下角 的按钮 来对文章内容作出评价, 也可以通过左下方的 关注按钮 来关注我的博客的最新动态. 如果文章内容对您有帮助, 不要忘记点击右下角的 推荐按钮 来支持一下哦 如果您对文章内 ...

  8. Android 使用java.net.socket 的接收问题

    // 初始化socketsocket = new Socket(InetAddress.getByName(sip), sport);InputStream sin = socket.getInput ...

  9. WPF 创建桌面快捷方式

    #region 创建桌面快捷方式 string deskTop = System.Environment.GetFolderPath(System.Environment.SpecialFolder. ...

  10. [SQL SERVER 2005]数据库差异备份及还原

    因为之前遇到还原差异备份,最开始遇到SQLServer报错:”无法还原日志备份或差异备份,因为没有文件可用于前滚“.查阅很多资料后,终于得到解决.收集整理成这篇随笔. 问题原因:出现这种错误绝大多数是 ...