XAF 属性编辑器(PropertyEditor)- 原理篇
前言
随着 DEV24.1.3 的发布,XAF Blazor 中的属性编辑器(PropertyEditor)也进行了很大的改动,在使用体验上也更接近 WinForm 了,由于进行了大量的封装,理解上没有 WinForm 直观,所以本文通过对属性编辑器的原理进行解析,并对比新旧版本中的变化,使大家能够对属性编辑器有一个更全面的认识。
原理
XAF 可以创建与平台无关的业务代码,而 PropertyEditor 就是它们与各个平台之间的一个桥梁,也就是说 PropertyEditor 每个平台都有各自的实现。从表面上看 PropertyEditor 的原理并不复杂,BO 中属性的更改会触发 PropertyEditor 中值的更改,而 PropertyEditor 值的更改又会更新具体平台组件的值,反过来也是一样,组件值的更改会触发 PropertyEditor 值的更改,而PropertyEditor 值的更改又会更新 BO 中的属性值。

如果我们使用的是XPO,PersistentBase 是全部 BO 的基类,它实施一个 INotifyPropertyChanged 接口,我们可以通过 INotifyPropertyChanged 接口来监听每一个属性的变化,这样我们就可以在属性值发生变化时通知 PropertyEditor,而这个监听工作是在 DetailView 中完成的。DetailView 在监听到 BO 中属性值发生更改时,会查找到具体的 PropertyEditor,并调用它的 Refresh 方法。
PropertyEditor 的属性(如:Caption,DisplayFormat)大部分来自 XAF 的 Model,也就是在 PropertyEditor 初始化时会传递一个 IModelMemberViewItem 对象,它里面包含了我们在模型编辑器中设置的值或一些默认值。
PropertyEditor 中有两个比较重要的方法 ReadValue 与 WriteValue,我一开始看到这个两方法时也产生了混淆,ReadValue 与 WriteValue 它们针对的对象是 BO 中的属性,而不是 PropertyEditor,也就是说 ReadValue 是读取 BO 中属性的值,而 WriteValue 是将值写入到属性中。
PropertyEditor 中还有一个 Control 属性,它的类型是 Object,不同的平台它返回的类型是不一样的,这个也是各个平台的组件,WinForm 返回的是 Control 类型,Blazor 返回的是 ComponentAdapter 或 ComponentModel (24.1.3之后 XAF 自带编辑器默认返回类型)。由于不同的平台渲染方式不同,对于 WinForm 来说,它返回的是 Control 类型,可以直接将其放置到父组件的 Controls 中,而对于 Blazor 就不行,Blazor 组件就不能像 WinForm 控件那样操作,它是通过 RenderFragment 进行组合在一起的,所以 Blazor 中的 PropertyEditor 同时还实施了一个 IComponentContentHolder 接口,通过它可以返回一个 RenderFragment。
在对外暴露组件时,Blazor 比 WinForm 要多一步,Blazor 中的 RenderFragment 是用于渲染组件的,不能通过 Control 属性返回,同时我们也无法直接操作 RenderFragment,我们是通过 ComponentModel 间接操作 Blazor 组件渲染的,所以当我们在外部想自定义 PropertyEditor 中的组件时,WinForm 是直接操作 Control,而 Blazor 是通过 ComponentModel 来完成。
PropertyEditor 的大部分子类都是围绕上面提到的属性或方法进行封装,以适应不同的平台。对于 WinForm 来说相对比较简单,就是直接操作 Control,而对于 Blazor 来说就要繁琐一些,就因为这样 XAF 针对 Blazor PropertyEditor 创建,做了大量的封装,特别是在最新的24.1.3中丢弃了 ComponentAdapter,使 PropertyEditor 的创建更加简单,甚至比 WinForm 还要简洁一些。下面主要以 Blazor 为主介绍 PropertyEditor 的相关技术点。
由于本文讲的是 PropertyEditor 的原理,默认读者是熟悉 PropertyEditor 的创建,所以不会再去讲解 PropertyEditor 的创建过程,而是只讲解它的技术点,如果对 PropertyEditor 的创建不熟悉的小伙伴,可以查看 XAF 的官方文档。
在 XAF 新版本中 ComponentAdapter 被废弃了,那它被引入的原因及被废弃的原因是什么呢?在 XAF Blazor 创建之初 ComponentAdapter 就已存在,通过它的名字我们知道它是一个代理层,负责 PropertyEditor 与 ComponentModel 之间的通讯。那为什么要加入这个代理层呢,而不是 PropertyEditor 直接操作 ComponentModel 呢。这里主要考虑是 PropertyEditor 的封装,由于 PropertyEditor 的操作基本是固定的(如,读值、写值及一些常规属性的设置),而 ComponentModel 是针对不同的组件的,不同的组件会有不同的属性,比如类似值属性,文本框是Text,日期框是Date,数值框是Value等,通过 ComponentAdapter 来适配不同的 ComponentModel(如:GetValue,SetValue 等),PropertyEditor 再去操作 ComponentAdapter ,这样更利于 PropertyEditor 的封装。
那在新版本中为什么 ComponentAdapter 又被废弃了呢,通过 XAF 的博客可以了解到,由于增加了 ComponentAdapter,使创建自定义 PropertyEditor 变的比较繁琐,移除 ComponentAdapter 后,可以使 PropertyEditor 的创建更接近于 WinForm。在没有了 ComponentAdapter 后,是不是 PropertyEditor 直接操作 ComponentModel 了呢,如果是那样的话,就会出现前面所讲到的,这会增加自定义 PropertyEditor 的复杂度,那新版是如何实现的呢。新版中是通过接口的方式来替代 ComponentAdapter,如新版中增加了一个 IHandleValueComponentModel 接口,通过这个接口 PropertyEditor 就可以获取、更新或监听组件值的变化,同时又增加了 DxComponentModelBase 这样的一个基类,它包含了一些常用的属性。也就是说新版是通过增加不同的接口及扩展基类的方式来替代 ComponentAdapter,这样在简化自定义 PropertyEditor 的同时,也保持了 PropertyEditor 的灵活性。
ComponentModel 在新版中还增加了一个 ComponentType 属性,XAF 通过 ComponentType 属性,可以自动完成 Renderer 的创建及属性的赋值。在之前的版本中我们都是在 Renderer 中创建一个 Create 静态方法,将 ComponentModel 传递进去,Renderer 需要将 ComponentModel 中的属性一一赋值给组件,这个过程非常繁琐,特别是 XAF 自身的 Renderer,代码量非常的大。新版中通过 ComponentType 的组件类型实现组件自动创建的同时,还将 ComponentModel 的属性自动传递给组件(提示:ComponentModel 的属性要与组件的属性保持一致)。由于 XAF 中的 PropertyEditor 都是对 Blazor 组件的封装,在 XAF 中直接省掉了 Renderer,也就是在 XAF 中没有 Renderer 的相关代码了。
在新版中创建一个 Blazor PropertyEditor 则相当简单,首先创建一个继承自 DxComponentModelBase 的 ComponentModel,在 ComponentModel 中增加组件所需要的属性,如果是自定义组件需要创建一个 Renderer,如果是 DEV 自身的 Blazor 组件,则直接将组件赋值给 ComponentType,同时基于 BlazorPropertyEditorBase 再创建一个 PropertyEditor,重写 CreateComponentModel 方法,并返回 ComponentModel 实例,整个 PropertyEditor 创建过程就结束了,相对来说要比 WinForm 还要简洁一些。
总结
在日常的 XAF 开发中,不管是增强或是个性化定制,都离不开 PropertyEditor,简化 PropertyEditor 的创建过程,在降低创建 PropertyEditor 难度的同时,也能大幅提高自定义 PropertyEditor 在项目中的占比,提高用户操作体验。
https://www.cnblogs.com/haoxj/p/18255657
XAF 属性编辑器(PropertyEditor)- 原理篇的更多相关文章
- sprin源码解析之属性编辑器propertyEditor
目录 异常信息 造成此异常的原因 bean 配置文件 调用代码 特别说明: 异常解决 注册springt自带的属性编辑器 CustomDateEditor 控制台输出 属性编辑器是何时并如何被注册到s ...
- spring源码解析之属性编辑器propertyEditor
异常信息造成此异常的原因bean配置文件调用代码特别说明:异常解决注册springt自带的属性编辑器 CustomDateEditor控制台输出属性编辑器是何时并如何被注册到spring容器中的?查看 ...
- SpringMVC源码阅读:属性编辑器、数据绑定
1.前言 SpringMVC是目前J2EE平台的主流Web框架,不熟悉的园友可以看SpringMVC源码阅读入门,它交代了SpringMVC的基础知识和源码阅读的技巧 本文将通过源码(基于Spring ...
- SpringMVC类型转换器、属性编辑器
对于MVC框架,参数绑定一直觉得是很神奇很方便的一个东西,在参数绑定的过程中利用了属性编辑器.类型转换器 参数绑定流程 参数绑定:把请求中的数据,转化成指定类型的对象,交给处理请求的方法 请求进入到D ...
- (spring-第13回【IoC基础篇】)PropertyEditor(属性编辑器)--实例化Bean的第五大利器
上一篇讲到JavaBeans的属性编辑器,编写自己的属性编辑器,需要继承PropertyEditorSupport,编写自己的BeanInfo,需要继承SimpleBeanInfo,然后在BeanIn ...
- (spring-第12回【IoC基础篇】)JavaBean的属性编辑器
在spring实例化bean的最后阶段,spring利用属性编辑器将配置文件中的文本配置值转换为bean属性的对应值,例如: 代码0011 <bean id="car" cl ...
- Cesium原理篇:7最长的一帧之Entity(下)
上一篇,我们介绍了当我们添加一个Entity时,通过Graphics封装其对应参数,通过EntityCollection.Add方法,将EntityCollection的Entity传递到DataSo ...
- 微信技术分享:微信的海量IM聊天消息序列号生成实践(算法原理篇)
1.点评 对于IM系统来说,如何做到IM聊天消息离线差异拉取(差异拉取是为了节省流量).消息多端同步.消息顺序保证等,是典型的IM技术难点. 就像即时通讯网整理的以下IM开发干货系列一样: <I ...
- 属性编辑器,即PropertyEditor-->Spring IoC
在Spring配置文件里,我们往往通过字面值为Bean各种类型的属性提供设置值:不管是double类型还是int类型,在配置文件中都对应字符串类型的字面值.BeanWrapper填充Bean属性时如何 ...
- 推荐-zabbix原理篇
推荐-zabbix原理篇(1) 提交 我的留言 加载中 已留言 本文大纲 snmp介绍 监控流程 开源监控工具zabbix zabbix监控功能的实现 支持数据库存储类型 Zabbix架构中的组件 Z ...
随机推荐
- [FE] JS 判断当前是否在微信浏览器中的最新代码
注意以下使用了 const 定义未改变的变量,没有使用 var. function isWeChatBrowser () { const ua = window.navigator.userAgent ...
- Java Spring项目中的CORS跨域开启的几种方式
引 在服务器端开启跨域的原理,一般都是通过在HTTP Headers中的响应头的Access-Control-Allow-Origin指定放行的域,来完成的. Access-Control-Allow ...
- frp内网穿透器安装与介绍
1.NAT访问 2.FRP介绍 中文官方文档:https://gofrp.org/docs/ github:https://github.com/fatedier/frp/releases frp 采 ...
- Redis 5集群部署
1.redis特点 (1)基于内存 (2)可持久化数据 (3)具有丰富的数据结构类型,适应非关系型数据的存储需求 (4)支持绝大多数主流开发语言,如C.C++.Java.Python.R.JavaSc ...
- Java根据URL截图的4种方式
方案选择 XHTMLRenderer(不要用) PhantomJs(三方库,已停更) Puppeteer(Chrome团队开发和维护) Selenium(支持多浏览器.多语言,服务器需要安谷歌浏览器) ...
- 如何在M1 MACBOOK上准备好ORB-SLAM2的环境
1. 环境 M1 Macbook Air Parallels Desktop 17 关于虚拟机,在之前尝试了UTM,但是性能欠佳,卡顿情况比较多,而且未能解决联网问题,最终只能含泪放弃 Paralle ...
- ajax递归发送请求
简介 大家都知道浏览器在处理http网络请求的时候,不同的浏览器会有不一样的并发限制,下表是一些主流浏览器对 HTTP 1.1 和 HTTP 1.0 的最大并发连接数目: Browser HTTP/1 ...
- Selenium4自动化测试3--元素定位By.NAME,By.LINK_TEXT 和通过链接部分文本定位,By.PARTIAL_LINK_TEXT,css_selector定位,By.CSS_SELECTOR
4-通过名称定位,By.NAME name属性为表单中客户端提交数据的标识,一个网页中name值可能不是唯一的.所以要根据实际情况进行判断 import time from selenium impo ...
- Unraid 使用 Docker Compose 安装 Immich 套件无法启用人脸识别的原因及修复方法
原因 问题原因是官方教程中的 docker-compose.yml 指明的机器学习组件 immich-machine-learning 中的 container_name 与 也就是 docker-c ...
- 因为我的一次疏忽而带来的golang1.23新特性
距离golang 1.23发布还有两个月不到,按照惯例很快要进入1.23的功能冻结期了.在冻结期间不会再添加新功能,已经添加的功能不出大的意外一般也不会被移除.这正好可以让我们提前尝鲜这些即将到来的新 ...