1 | public class ImageButton:Button |
资源样式
1 | <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" |
Xaml
1 | <Window x:Class="ImageButton.MainWindow" |
自定义控件
1 | using System; |
资源样式
1 | <ResourceDictionary |
1 | public class ImageButton:Button |
1 | <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" |
1 | <Window x:Class="ImageButton.MainWindow" |
1 | using System; |
1 | <ResourceDictionary |
1.将导航的内容寄宿于窗口中
2.Xaml浏览器应用程序 扩展名.xbap 可以直接在浏览器中运行.
1.页面:WPF将导航内容封装为多个页面.
2.超链接
3.NavigationServices
4.Journal 每次连接通过Jourmal记录作为历史记录.
Page的宿主窗口包括浏览器,导航窗口和Frame.
NavigationWindow是一个顶层窗口,不允许嵌入到其他控件中,而Frame则为轻量级,可以嵌入到其他控件,如NavigationWindow或者Page,甚至其他Frame中.Frame默认没有导航工具栏,可以设置其NavigationUIVisiblity属性为Visible使其工具栏是否可见.
1 | <HyperLink NavigateUri="Page2.xaml">开始阅读路由事件 |
段落导航 NavigateUri的设置方法是”页面名#元素名”
HyperLink Click NavigationService Navigate方法导航.
1 | private Hyperlink_Click(object sender,RoutedEventArgs e){ |
NavigationCommands.BrowseBack NavigationCommands.BrowseForward
1 | <Page x:Class="WpfApp1.Pages.LoginPage" |
1 | <Window.CommandBindings> |
CommandBinding有两个重要事件,执行关联的Command时,会触发该Executed事件的处理函数,触发CanExecute事件时,相应的事件处理函数需要将传递来的参数e的CanExecute属性设为true或false.告知WPF命令系统该命令是否可用.
WPFCommand模型包含如下4部分:
1.Command:应用程序需要执行的任务.
2.CommandBinding:连接Comamnd和特定应用程序逻辑,如前面CommandBinding连接Save命令及其处理函数.
3.Command Source:触发Command的对象,如前述的菜单栏和工具栏,单击可以触发绑定的Command.
4.Command target:Command应用再上面的对象.如前述的TextBox.
1.ICommand接口
一个Command代表应用程序的任务.在WPF中所有Command都要实现ICommand接口,该接口有两个方法(Executed CanExecute)和一个事件(CanExecuteChanged)
1.Execute方法:当Command被触发时调用该方法,执行与命令相对应的操作.
2.CanExecute方法:用来判断该命令是否可应用到当前Command target上,如果该方法返回true可以
3.CanExecutedChanged事件:Command有执行或者不执行两种状态,状态改变时触发该事件.一般监听该事件的是CommandSource,它监听到该事件后会调用绑定的Command的CanExecute方法检查当前Command的状态,然后决定然后决定CommandSource是启用还是禁用.
Recommand的InputGuestures属性用来指定鼠标和键盘动作,从而可以关联命令和相应的鼠标键盘动作.
WPF内置的Command库
ApplicationCommands NavigationCommands EditingCommands ComponentCommands MeidaCommands
CommandSource是能触发Command的对象按钮和菜单,包括键盘和鼠标操作都可以是Command Source.
CommandSource必须实现ICommandSource接口,该接口定义了3个属性
1.Command:Command Source触发的Command.
2.CommandParameter:Command执行时需要的参数.大多数情况下命令的执行不需要参数.
3.CommandTarget:Command应用对象.
WPF中实现ICommandSource接口的有ButtonBase,MenuItem,Hyperlink和InputBinding.
CommandBinding关联Command和实现Command的事件处理函数
CommandBinding类包括Command属性,以及PreviewExecuted,Executed,PreviewCanExecute和CanExecute事件.如果一个元素派生自UIElement,ContentElement和UIElement3D之一,那么CommandBinding对象可以添加到该元素中.
1 | <Window.CommandBindings> |
Command Target是Command会应用在上面的对象.ComandSource 需要实现ICommandSource接口,其中就有一个属性是CommandTarget.当CommandSource不明确指定Command Target属性时,会把当前获得的焦点的元素认为是Comand Target.
1 | <Window x:Class="WpfApp1.BiaoZhuWindow" |
1 | namespace BookModels |
不过这种事件看起来不像.Net事件.改写后
1 | namespace BookModels |
1.委托类型名称以EventHandler结束,原型有一个void返回值并接受两个输入参数,即一个Object类型和一个EventArgs类型(或继承自EventArgs)
1 | public delegate void WhiteBeeEventHandler(object sender,WhiteBeeEventArgs e); |
2.事件的命名为委托去掉EventHandler之后剩余的部分.
1 | public event WhiteBeeEventHandler WhiteBee; |
3.继承自EventArgs的类型应该以EventArgs结尾.
1 | public class WhiteBeeEventArgs:EventArgs{ |
以Button的Click事件为例.该事件是个路由事件.
1 | public abstract class ButtonBase:ContentControl,ICommandSource{ |
同依赖属性一样,路由事件也需要注册,不同的是使用EventManager.RegisterRoutedEvent方法.
同依赖属性,用户不会直接使用路由事件,而是使用传统的Clr事件.有两种方式关联事件及其处理函数.
在代码中,仍然按照原方法关联和解除关联事件处理函数(+=/-=).
1 | Button b2=new Button(); |
传统的事件触发往往直接调用其委托(因为事件的本质是委托),而路由事件则通过一个RaiseEvent方法触发,调用该方法后所有关联该事件的对象都会得到通知.
1 | RoutedEventArgs e=new RoutedEventArgs(ClickEvent,this); |
路由事件通过EventManager.RegisterRoutedEvent方法注册,通过AddHandler和RemoveHandler来关联和解除关联的事件处理函数,通过RaiseEvent方法来触发事件,通过传统的CLR事件封装后供用户调用,使得用户同使用传统的CLR事件一样使用路由事件.
1.路由事件的旅行策略
旅行当中,一般只出现两种角色:1.事件源.由其触发事件,是路由事件的起点.2.是事件监听者,通常针对监听的事件有一个相应的事件处理函数,当路由事件经过事件监听者,就好比经过一个客栈,要做短暂停留,由事件处理函数来处理该事件.
路由事件的策略有如下三种:
1.Bubbing:事件从事件源出发一路上溯直到根节点,很多路由事件使用该策略.
2.Direct 事件从事件源出发,围绕事件源转一圈结束.
3.Tunneling 事件源触发事件后,事件从根节点出发下沉直到事件源.
最基本的路由事件处理函数原型
public delegate void RoutedEventHandler(Object sender,RoutedEventArgs e)
事件处理函数之间有微小差异.鼠标事件的处理函数原型
public delegate void MouseEventhandler(Object sender,MouseEventArgs e)
这种事件处理函数有如下两个特点
1.返回原型为void.
2.有两个参数,第一个是一个Object类型的对象.表示拥有该事件处理函数的对象.第二个是RoutedEventArgs或者是RoutedEventArgs的派生类.带有其路由事件的信息.
RoutedEventArgs结构包括4个成员变量.
Source 表明触发事件的源 如当键盘事件发生时,触发事件的源是当前获得焦点的对象.当鼠标事件发生时,触发事件的源是鼠标所在的最上层对象
OriginalSource 表明触发事件的源.一般来说OriginalSource和Source相同,区别在于Source表示逻辑树上的元素;OriginalSource是可视树中的元素.如单击窗口的边框,Source为Window,OriginalSource为Border.
RoutedEvent 路由事件对象
Handled 布尔值 为true 表示该事件已处理,这样可以停止路由事件.
Handled属性是改变路由事件旅行的元凶,一旦在某个事件处理函数中将Handled的值设置为true.路由事件就停止传递.
一个事件被标记为处理,事件处理函数则不可处理该事件,WPF提供了一种机制,即使事件被标记为处理,事件处理函数仍然可以处理.但是关联事件及其处理函数需要稍作处理.AddHandler重载了两个方法,其中之一如下,需要将第三个参数设为true.
public void Addhandler(RoutedEvent routedEvent,Delegate handler,bool handledEventsToo)
事件处理函数有两种类型,一是前面所说的普通事件处理函数.二是通过EventManager.RegisterClassHandler方法将一个事件处理函数和一个类关联起来,这种事件处理函数,
称为类事件处理函数.其优先权高于前者.也就是说事件在旅行时,会先光临类事件处理函数,然后再光临类事件处理函数.
1 | public class MySimpleButton:Button{ |
依赖属性是一种类型为DependencyProperty的属性,其依赖属性标识则是依赖属性的实例.
1.DependencyObject:继承该类后才可以注册和拥有依赖属性
2.WPF属性系统:WPF通过提供一系列服务扩展普通的.Net属性.这些服务总称为WPF属性系统.
3..Net属性包装器:指属性的get和set的实现.在这个实现中均调用DependencyObject的GetValue和SetValue方法.
1.依赖属性对资源引用的支持
2.依赖属性对样式的支持
3.依赖属性对动画的支持
4.依赖属性对数据绑定的支持
5.依赖属性对属性值继承的支持
6.依赖属性对元数据重载的支持
依赖属性和普通.Net属性区别之一是有一个元数据对象.通过设置元数据对象,可以改变依赖属性的状态和行为.一般用到的元数据类是PropertyMetaData和FrameworkPropertyMetaData,前者是后者的基类.
PropertyMetaData—>UIPropertyMetaData—>FrameworkPropertyMetaData.
一般依赖属性的元数据类型为PropertyMetaData,而大部分控件的依赖属性,如按钮的WIdth及Background这样的依赖属性就会用到FrameworkPropertyMetaData元数据对象.
一般元数据对象包括如下类型的信息:
1.默认值
2.引用回调函数 其中PropertyChangedCallback,在属性值发生改变时调用;CoerceValueCallback用于限制属性值.
3.如果是框架级别的一些属性,则会有一些标识告知WPF该属性的某些状态信息.
7.依赖属性对WPF设计器的集成支持
###依赖属性的组成部分
1 | public static DependencyProperty Register(string name,Type propertyType,Type ownerType,PropertyMetadata typeMetadata,ValidateValueCallback validateValue validateValueCallback) |
第一个参数是指的属性名,这个名字和依赖属性相关的.Net属性名相同,第二个参数是指该.Net属性的类型.第三个属性是指该依赖属性属于什么类型.第四个参数是依赖属性的元数据.第五个参数是值验证的回调函数.该回调函数是负责检验值的最后一道关卡.
实现依赖属性必须满足以下条件:
1.该类必须继承自DependencyObject类.只有DependencyObject类才可以注册和拥有依赖属性.
2.该类中必须定义一个public static readonly成员变量,类型为DependencyProperty.
3.该依赖属性必须以属性名+Property命名
4.必须调用DependencyProperty的注册方法,在WPF属性系统中注册该依赖属性或者使用依赖属性的AddOwner方法.两种方法均返回一个DependencyProperty类型的标识并将其保存在定义的DependencyProperty成员变量中.
5.为依赖属性实现一个.Net属性包装器.
1 | //依赖属性 |
1 | static SpaceWindow(){ |
注册依赖属性Space不是通过注册而来,而是从SpaceButton的Space属性的AddOwner方法得来的.
即依赖属性可以选择把自身添加给其他属性,这是普通属性不可实现的.需要特别注意元数据不能再使用,必须新建一个,为了实现属性值继承,将Inherit标识为true.
1.直接设置的值>样式中触发器设置的值>样式中Setter设置的值.
优先级列表.
1.限制 Coerce 2.动画 3. 本地值 包括再代码和Xaml中直接设置的值,以及动态资源引用和数据绑定.
4.模板的父类 TemplateParent Triggers Setters 在模板的父类中Triggers设置依赖属性值的优先级高于在Setter中设置依赖属性值.5.样式触发器 主要指在Application或者Page中的样式,不包括主题样式.
6.模板触发器 7.样式设置 8.主题样式 9.属性值继承 10.元数据的默认值
附加属性实质上是一个依赖属性,与普通的依赖属性相比有以下不同
1.注册不再是通过Register方法注册,而是通过RegisterAttached方法注册.
2.没有普通的.Net属性包装器,而是通过Get和Set属性名来实现属性包装.
3.没有普通的.Net属性.
一个附加属性IsBubbleSource
1 | public static readonly DependencyProperty IsBubbleSourceProperty=DependencyProperty.RegisterAttached("IsBubbleSource",typeof(Boolean),typeof(AquariumObject),new FrameworkPropertyMetadata(false,FrameworkPropertyMetadataOptions.AffectsRender)); |