WPF依赖属性和路由事件
WPF依赖属性及路由事件
依赖属性
概念
依赖属性是标准.NET属性的全新实现。在WPF的核心特性(如动画、数据绑定以及样式)中需要嵌入依赖属性。简言之,依赖属性就是一种可以自己没有值,并能通过使用Binding从数据源获得值(依赖在别人身上)的属性。拥有依赖属性的对象成为“依赖对象”。
依赖属性优点:
- 节省实例堆内存的开销
- 属性值可以通过Binding依赖在其他对象上
原理
传统.NET开发中,一个对象占用的内存空间在调用new操作符进行实例化的时候就已经决定了,而WPF允许对象在被创建时并不包含用于储存数据的空间、只保留在需要用到数据时能够获得默认值、借用其他对象数据或实施分配空间的能力——这种对象就称为依赖对象(Dependency Object)而他这种实时获取数据的能力则依靠依赖属性(Dependency Property)来实现。WPF开发中,必须使用依赖对象作为依赖属性的宿主。
依赖对象的概念被DependencyObject类实现,依赖属性则由DependencyProperty类实现。DependencyObject具有GetValue和SetValue两个方法。
public class DependencyObject : DispatcherObject { public Object GetValue(DependencyProperty dp) { //.. } public void SetValue(DependencyProperty dp,Object Value) { //.. } }
这两个方法都以DependencyProperty对象为参数,GetValue和SetValue两个方法分别通过DependencyProperty对象获取值和储存值,将DependencyObject和DependenctProperty紧密结合在一起。
从上面继承树可以看到,WPF的所有UI空间都是依赖对象。
声明和使用依赖属性
Public class Student { //注册依赖属性 public static ReadOnly DependencyProperty NameProperty; //Clr属性包装器,方便对依赖属性进行访问,无法关心内部如何实现 public string Name { Get { return (string)GetValue(NameProperty); } Set { SetValue(NameProperty,value); } } Static Student { NameProperty = DependencyProperty.Register("Name",typeof(string),typeof(Student),new PropertyMetadata("默认值", new PropertyChangedCallback(NameChangedCallback))); } }
// // 摘要: // 使用指定的属性名称、属性类型、所有者类型和属性元数据注册依赖属性。 // // 参数: // name: // 要注册的依赖属性的名称。 // // propertyType: // 属性的类型。 // // ownerType: // 正在注册依赖属性的所有者类型。 // // typeMetadata: // 依赖属性的属性元数据。 // // 返回结果: // 一个依赖属性标识符,应使用它来设置类中 public static readonly 字段的值。 稍后将此标识符用来引用依赖属性,从而实现以编程方式设置其值或获取元数据等操作。 public static DependencyProperty Register(string name, Type propertyType, Type ownerType, PropertyMetadata typeMetadata);
WPF依赖属性优先级:
路由事件
声明和使用路由事件
public class Student { //声明路由事件 public static ReadOnly RoutedEvent NameChangedEvent; //包装路由事件 public event NameChanged { add{AddHandler(NameChangedEvent, value);} remove{RemoveHandler(NameChangedEvent,value);} } //注册路由事件 static Student() { NameChangedEvent = EventManager.RegisterRoutedEvent("NameChanged", RoutingStrategy.Bubble, typeof(EventHandler<NameChangedEventArgs>), typeof(Student)); } } //事件参数定义 public class NameChangedEventArgs : RoutedEventArgs { public NameChangedEventArgs(RoutedEvent routedEvent, object source) : base(routedEvent, source) { } /// <summary> /// 改变前名称 /// </summary> public double PreName { get; set; } /// <summary> /// 改变后名称 /// </summary> public double ChangedName { get; set; } }
RoutedEvent 路由事件
EventHandle
事件处理器 包含自定义参数
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)