WPF进阶技巧和实战05-样式与行为
样式(style)是组织和重用格式化选项的重要工具。创建一系列封装某些细节的样式,然后通过属性来应用样式。
行为(behavior)是一款重用用户界面代码更有挑战性的工具。基本思想是:使用行为封装一些通用的UI功能。如果具有适当的行为,可使用一两行XAML标记将其附加到任何元素。
样式基础
样式就是可应用于元素的属性值集合。样式支持触发器,当属性发生变化时,可通过触发器改变控件的样式。
样式有5个重要属性:
属性 | 说明 |
---|---|
Setters | 设置属性值,自动关联事件处理程序的Setter对象或者EventSetter对象的集合 |
Triggers | 继承自TriggerBase类,并能自动改变样式设置的对象集合。例如,当另一个属性改变时,或者当发生某个事件时,可以修改样式 |
Resources | 希望用于样式的资源集合。例如,可能需要使用一个对象设置多个属性。这时,更高效 的做法是作为资源创建对象,然后再Setter对象中使用该资源(而不是使用嵌套的标签为每一个Setter对象的一部分创建对象) |
BasedOn | 通过该属性可创建继承自(并且可以选择地进行重写)其他样式设置的更具体形式 |
TargetType | 该属性标识应用样式的元素类型。通过该属性可创建只影响特定类型元素的设置器,还可以创建能够为恰当的元素类型自动起作用的设置器 |
<Style x:Key="TextBlockBaseStyle" TargetType="{x:Type TextBlock}">
<Setter Property="TextWrapping" Value="NoWrap" />
<Setter Property="TextTrimming" Value="None" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="Width" Value="Auto" />
<Setter Property="Height" Value="Auto" />
</Style>
触发器
使用触发器,可以自动完成简单的样式改变,例如,当属性发生改变时进行相应,并自动调整样式。触发器通过Style.Triggers集合链接到样式。每个样式都可以有任意多个触发器,而且每个触发器都是TriggerBse的派生类实例。
名称 | 说明 |
---|---|
Trigger | 最简单的触发器,可以监测依赖项属性的变化,然后使用设置器改变样式 |
MutiTrigger | 和Trigger类似,但是触发器联合了多个条件。只有满足所有条件,才会启动触发器 |
DataTrigger | 这种触发器使用数据绑定,与Trigger类似,只不过监测是任意绑定数据的变化 |
MultiDataTrigger | 联合多个数据触发器 |
EventTrigger | 最复杂的触发器,当事件发生时,这种触发器应用动画 |
简单触发器
每个简单的触发器都指定了正在监视的属性,以及正在等待的属性值。触发器的优点是不需要为翻转他们而编写任何逻辑。只要停止触发器(条件不满足时),元素就会恢复到之前的属性值。
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Opacity" Value=".9" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Opacity" Value=".6" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Opacity" Value="0.4" />
</Trigger>
</Style.Triggers>
触发器的顺序决定了哪个触发器最终生效,最后的触发器会生效。
如果希望创建只有当几个条件都成立时才激活的触发器,就可以使用MutiTrigger。这种触发器提供了一个Conditions集合,可通过该集合定一系列触发条件,这些条件不分先后顺序,只有全部满足时,触发器才会工作。
事件触发器
普通触发器等待属性发生变化,而事件触发器等待特定的事件被触发。事件触发器要求用户提供一系列修改控件的动作,这些动作通常被用作动画。
行为
基本思想:创建封装了一些通用用户界面功能的行为。这一功能可以是基本功能(如启动故事板或导航到超链接),也可以是复杂功能(如处理多点触摸交互,或构建使用实时物理引擎的碰撞模型)。一旦构建功能,就可将他们添加到任意应用程序的另一个控件中,具体方法是将该控件链接到适当的行为并设置行为的属性。
using Microsoft.Xaml.Behaviors;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace Course04
{
public class DragInCanvasBehavior : Behavior<UIElement>
{
protected override void OnAttached()
{
base.OnAttached();
this.AssociatedObject.MouseLeftButtonDown += AssociatedObject_MouseLeftButtonDown;
this.AssociatedObject.MouseMove += AssociatedObject_MouseMove;
this.AssociatedObject.MouseLeftButtonUp += AssociatedObject_MouseLeftButtonUp;
}
protected override void OnDetaching()
{
base.OnDetaching();
this.AssociatedObject.MouseLeftButtonDown -= AssociatedObject_MouseLeftButtonDown;
this.AssociatedObject.MouseMove -= AssociatedObject_MouseMove;
this.AssociatedObject.MouseLeftButtonUp -= AssociatedObject_MouseLeftButtonUp;
}
Canvas canvas = null;
bool isDragging = false;
Point mouseOffset;
private void AssociatedObject_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
if(isDragging)
{
this.AssociatedObject.ReleaseMouseCapture();
isDragging = false;
}
}
private void AssociatedObject_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
if(isDragging)
{
Point point = e.GetPosition(canvas);
this.AssociatedObject.SetValue(Canvas.LeftProperty, point.X - mouseOffset.X);
this.AssociatedObject.SetValue(Canvas.TopProperty, point.Y - mouseOffset.Y);
}
}
private void AssociatedObject_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
if(canvas == null)
{
canvas = (Canvas)VisualTreeHelper.GetParent(this.AssociatedObject);
}
isDragging = true;
mouseOffset = e.GetPosition(this.AssociatedObject);
this.AssociatedObject.CaptureMouse();
}
}
}
XAML代码:
<Window
x:Class="Course04.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Course04"
Title="MainWindow"
Width="800"
Height="450"
mc:Ignorable="d">
<Grid>
<MediaElement LoadedBehavior="Play" Source="Normal.wav" Visibility="Collapsed" />
<Canvas>
<Rectangle Canvas.Left="60" Canvas.Top="20" Width="40" Height="50" Fill="Red" />
<Ellipse Canvas.Left="80" Canvas.Top="100" Width="80" Height="50" Fill="Green">
<b:Interaction.Behaviors>
<local:DragInCanvasBehavior />
</b:Interaction.Behaviors>
</Ellipse>
<Rectangle Canvas.Left="70" Canvas.Top="200" Width="40" Height="50" Fill="Yellow" />
</Canvas>
</Grid>
</Window>
WPF进阶技巧和实战05-样式与行为的更多相关文章
- WPF进阶技巧和实战03-控件(3-文本控件及列表控件)
系列文章链接 WPF进阶技巧和实战01-小技巧 WPF进阶技巧和实战02-布局 WPF进阶技巧和实战03-控件(1-控件及内容控件) WPF进阶技巧和实战03-控件(2-特殊容器) WPF进阶技巧和实 ...
- WPF进阶技巧和实战03-控件(4-基于范围的控件及日期控件)
系列文章链接 WPF进阶技巧和实战01-小技巧 WPF进阶技巧和实战02-布局 WPF进阶技巧和实战03-控件(1-控件及内容控件) WPF进阶技巧和实战03-控件(2-特殊容器) WPF进阶技巧和实 ...
- WPF进阶技巧和实战08-依赖属性与绑定01
依赖项属性 定义依赖项属性 注意:只能为依赖对象(继承自DependencyObject的类)添加依赖项属性.WPF中的元素基本上都继承自DependencyObject类. 静态字段 名称约定(属性 ...
- WPF进阶技巧和实战07--自定义元素01
完善和扩展标准控件的方法: 样式:可使用样式方便地重用控件属性的集合,甚至可以使用触发器应用效果 内容控件:所有继承自ContentControl类的控件都支持嵌套的内容.使用内容控件,可以快速创建聚 ...
- WPF进阶技巧和实战06-控件模板
逻辑树和可视化树 System.Windows.LogicalTreeHelper System.Windows.Media.VisualTreeHelper 逻辑树类(LogicalTreeHelp ...
- WPF进阶技巧和实战03-控件(5-列表、树、网格02)
数据模板 样式提供了基本的格式化能力,但是不管如何修改ListBoxItem,他都不能够展示功能更强大的元素组合,因为了每个ListBoxItem只支持单个绑定字段(通过DisplayMemberPa ...
- WPF进阶技巧和实战03-控件(5-列表、树、网格01)
列表控件 ItemsControl为列表项控件定义了基本功能,下图是ItemsControl的继承关系: 在继承自ItemsControl类的层次结构中,还显示了项封装器(MenuItem.TreeV ...
- WPF进阶技巧和实战09-事件(1-路由事件、鼠标键盘输入)
理解路由事件 当有意义的事情发生时,有对象(WPF的元素)发送的用于通知代码的消息,就是事件的核心思想.WPF通过事件路由的概念增强了.NET事件模型.事件由允许源自某个元素的事件由另一个元素引发.例 ...
- WPF进阶技巧和实战09-事件(2-多点触控)
多点触控输入 多点触控输入和传统的基于比的输入的区别是多点触控识别手势,用户可以移动多根手指以执行常见的操作,放大,旋转,拖动等. 多点触控的输入层次 WPF允许使用键盘和鼠标的高层次输入(例如单击和 ...
- WPF进阶技巧和实战07--自定义元素02
在01节中,研究了如何开发自定义控件,下节开始考虑更特殊的选择:派生自定义面板以及构建自定义绘图 创建自定义面板 创建自定义面板是一种比较常见的自定义控件开发子集,面板可以驻留一个或多个子元素,并且实 ...
随机推荐
- 怎样在自己的 Web 中加入强大的日志系统系统?slf4j 的日志插件必须要知道!
对于程序猿来讲,一个应用程序的日志管理是极为重要的.因为,它可以帮助我们随时查看应用程序的运行状态.执行效果等信息,从而监控软件系统.或是根据日志信息解决一些重要的问题. 但是在 Java 应用程序中 ...
- Socket通信协议解析(文章摘要)
参考网址: https://zhuanlan.zhihu.com/p/84800923 在计算机通信领域,socket 被翻译为"套接字",它是计算机之间进行通信的一种约定或一种方 ...
- 详解C#中 Thread,Task,Async/Await,IAsyncResult的那些事儿
说起异步,Thread,Task,async/await,IAsyncResult 这些东西肯定是绕不开的,今天就来依次聊聊他们 1.线程(Thread) 多线程的意义在于一个应用程序中,有多个执行部 ...
- 通用Mapper学习
<通用Mapper>部分注解 @Table(name="tableName")用法: 这个注解写在实体类的上面 指定数据库表的名字作用: 建立实体类和数据库表之间 ...
- SpringCloud升级之路2020.0.x版-24.测试Spring Cloud LoadBalancer
本系列代码地址:https://github.com/HashZhang/spring-cloud-scaffold/tree/master/spring-cloud-iiford 通过单元测试,我们 ...
- 原生 JS 与 jQuery 中的 AJAX
AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML). AJAX 最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更 ...
- webpack编译后的代码如何在浏览器执行
浏览器是无法直接使用模块之间的commonjs或es6,webpack在打包时做了什么处理,才能让浏览器能够执行呢,往下看吧. 使用commonjs语法 先看下写的代码, app.js minus.j ...
- C# - 习题05_写出程序的输出结果o1.count
时间:2017-08-24 整理:byzqy 题目:写出下列程序的输出结果: //原题程序如下: class Class1 { private static int count = 0; static ...
- 用C++实现的Euler筛法程序
Euler筛法介绍 以筛出100以内(含100)的所有素数为例来说明一下欧拉筛法的原理. 和Eratosthenes筛法一样,Euler筛法也从2开始筛,但Eratosthenes筛法会把2的倍数一批 ...
- kubebuilder实战之八:知识点小记
欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...