WPF
布局
Button的组成
控件(Button) └── Style(样式) ├── Setter 1: 设置 Background = "Green" ← 控制属性 ├── Setter 2: 设置 FontSize = "14" ← 控制属性 ├── Setter 3: 设置 Template = {...} ← 引用模板 │ └── ControlTemplate(控件模板) │ ├── Grid ← 定义视觉树 │ ├── Ellipse ← 定义视觉树 │ └── ContentPresenter ← 定义视觉树 └── Triggers ← 控制交互行为
MVVM模式
Model
数据的存储
ViewModel
View和Model的桥梁,暴露属性和命令,通过属性绑定驱动 View 更新,通过命令处理用户交互。
View
负责展示数据和响应用户操作,不执行任何业务逻辑
Blinding
目标(Target)➡绑定源(Sourse),一般为ViewModel➡绑定对象(path)
确立绑定的“默认数据来源”(Datacontext)
将View里的作用域和ViewModel连接
显示功能的实现
实现接口:INotifyPropertyChanged里的PropertyChanged事件
监听协议,会自动加载到UI
四种模式(Mode)
OneWay TwoWay OneTime OneWayToSourse
触发时机(UpdateSourceTrigger)
“源”(ViewModel)流向“目标”(UI)
触发PropertyChanged事件
UI 到 ViewModel(目标 → 源)
PropertyChanged
每输入一个字符/每操作一次,立即更新 ViewModel。
LostFocus
失去键盘焦点时才更新
Explicit
不自动更新,必须手动调用 BindingExpression.UpdateSource() 才会更新。
TemplateBinding:TemplatedParent的语法糖
模板内部的属性跟随控件本身的属性变化
指定源的4种方式
默认Datacontext
沿着可视化树查找
元素名称:ElementName
通过 x:Name 引用界面上的另一个控件
相对源: RelativeSource
四种相对源绑定
Self(绑定到自身)
FindAncestor(查找上级祖先)
PreviousData(上一个数据项)
TemplatedParent(模板化父级)
静态资源:Source
指向一个静态对象或静态属性(如 {x:Static})
资源(Resources)
本质上就是一个 Dictionary<object, object> 的键值对集合,WPF 资源可以存储任何 CLR 对象,(值类型:结构体,枚举;接口:不是实例)不行
常见的六种
样式(Style)
控件模板(ControlTemplate)
数据模板(DataTemplate)
转换器(Converter)
静态资源值(字符串、数字、颜色画刷、字体等)
自定义类 / 共享对象
x:key
Style 时只指定 TargetType,不写 x:Key,那么这个样式会自动应用到作用域内所有匹配类型的元素,其他类型不写会报错
资源字典(ResourceDictionary)的“合并”机制
概念:目标类型中属性的预设值
x:Key
唯一标识
TargetType
目标控件类型
BasedOn
继承父样式
<Style.Resources>
样式内部的局部资源(仅该样式内部可用)
< Setter>
Setter Property的多种方式
Property + Value
<Setter.Value>
使用 StaticResource 引用
使用 Binding(数据绑定)
<Style.Triggers>
触发器(Trigger)
属性触发器(Trigger)
监听控件自身的依赖属性
IsEnabled
IsChecked
IsFocused
IsMouseOver
多条件属性触发器(MultiTrigger)
监听控件自身的多个依赖属性
< MultiTrigger> <MultiTrigger.Conditions> </MultiTrigger.Conditions>
数据触发器(DataTrigger)
任意绑定的数据
< DataTrigger Binding="{Binding 路径}" Value="目标值"> < Setter Property="属性名" Value="新值"/> < /DataTrigger>
多条件数据触发器(MultiDataTrigger)
任意绑定的多个数据
< MultiDataTrigger> <MultiDataTrigger.Conditions> </MultiDataTrigger.Conditions>
路由事件(EventTrigger)
模板(Template)
控件模板(ControlTemplate),作用于控件
视觉树(Visual Tree)
指定控件种类:TargetType=""
用 TemplateBinding 把模板内子元素的属性(如 Background)绑定到Fill
ContentPresenter 或 ItemsPresenter 设置占位符
数据模板(DataTemplate),作用于数据
给遇到某种类型的数据,设置一种 UI 结构来展示它
应用方式
隐式模板:DataType="{x:Type local:DeviceData}"
显示模板:有 x:Key,如 x:Key="DeviceCardTemplate"
属性
普通属性
值存储在私有字段中
可通知属性
MVVM 数据绑定的机制:普通属性 + 实现INotifyPropertyChanged 接口里的PropertyChanged事件,在set方法里触发
依赖属性(Dependency Property)
WPF属性系统管理的、支持绑定、动画、样式、继承等高级功能的特殊属性
依赖属性(DependencyProperty)本身就内置了值变化通知系统。
当依赖属性的值发生变化时,WPF 的绑定引擎会自动将新值推送到绑定的 UI 元素上。
值存储在WPF属性系统的全局字典中
public static readonly DependencyProperty SpeedProperty = DependencyProperty.Register()
定义一个名为SpeedProperty,类型是DependencyProperty 的对象,通过DependencyProperty.Register()这个静态方法创建并且返回DependencyProperty 类型的实例
附加属性(Attached Property)
可以"附加"到其他控件上的依赖属性。它允许一个控件为另一个控件定义属性值,而不需要修改被附加控件的代码
模式·
父容器定义,子元素设置
子元素定义,父容器使用
服务类定义,任何对象使用
注册方法:RegisterAttached
必须提供静态的 Get/Set 方法(命名规范:Get/Set + 属性名)
新主题
转换器(Convert)
实现 IValueConverter 接口的类,用于在绑定源(数据)和绑定目标(UI)之间进行值的双向转换
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
value:要转换的值
targetType:目标类型
parameter:在 XAML 中通过 ConverterParameter 传入的额外配置参数
culture:当前线程的区域文化信息
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
什么时候调用:触发 PropertyChanged 事件, WPF 绑定引擎检测到变化,获取绑定的 Converter,调用
高级转换器
实现IMultiValueConverter接口的类
命令(Command)
定义:是WPF中一种“将‘操作意图’封装成对象,并自带‘是否可执行’状态通知机制”的编程模型。
三个部分
Execute(执行体)
CanExecute(可执行性)
CanExecuteChanged((状态通知))
路由事件(RoutedEvent)
允许事件在元素树(Visual Tree 或 Logical Tree)中沿着特定路径进行传播,而不仅仅是直接在事件源上触发
在路由事件里做了什么
创建了一个携带事件信息的参数对象,类是:RoutedEventArgs(RoutedEvent routedEvent, object source)
routedEvent(要触发的事件标识)
source(事件源)
RaiseEvent:触发事件
RaiseEvent 是 UIElement 类提供的方法,所有 WPF 控件都继承自它。
这个方法会将事件提交给 WPF 路由引擎,由引擎负责沿视觉树传播。
e.Handled = true(阻止事件传播)
行为
概念:Behavior(行为) 就像一个“临时插件”。你把它拖到任何WPF控件上,那个控件就会立刻获得新技能,而你完全不用修改控件本身的代码
继承Behavior<控件种类>
重写 Behavior 基类的方法
OnAttached()
添加订阅
OnDetaching()
取消订阅
其他内容
AssociatedObject属性
获取 Behavior 所依附的控件实例
依赖注入(DI)
消息/事件聚合器
虚拟化(Virtualization)
用户控件和自定义控件
用户控件(UserControl)
作用
封装 UI 片段:把一组相关控件打包成一个可复用的新控件
封装逻辑:把子控件的交互逻辑封装在控件内部
继承基类:继承自 UserControl
不修改样式和空间模板,UI 是固定的
自定义控件(CustomControl)
继承基类:继承自 Control 或其子类(如 Button、ItemsControl)
可以通过 Style 和 ControlTemplate 定制外观
作成者