避免propertyChanged事件二次触发方案原创
金蝶云社区-蒋经东
蒋经东
15人赞赏了该文章 1,184次浏览 未经作者许可,禁止转载编辑于2023年12月18日 14:48:41

苍穹监听动态表单,字段变化时,会触发propertyChanged事件


有时候我们有一个简单的业务需求:如果输入的值不是数字,则清空该字段为空,此时就会在代码设置字段值为null

如该方法:

image.png

引发的现象是,界面输入一次值时,触发一次propertyChanged,做了相关是否是数字判断,不符合着设置为null,这时候又触发了一次propertyChanged,虽然不会影响最终结果,但是连续触发两次,感觉很变扭,也很影响性能


产生疑问:是否可以设置参数,特殊情况下不触发propertyChanged

跟了一遍propertyChanged的值变化触发源码:

image.png

可以看出,只要有值变化,就会触发值更新,然后一定会调用propertyChanged方法,没有if else 或者 参数控制否是调用propertyChanged,是一定会调用。。。。


所以结论是,只要是值更新,一定会调用propertyChanged方法,没办法控制

最终翻阅了社区,找到一种方法可以避免二次调用propertyChanged的解决方案:

1、设置一个全局的变量,放到苍穹的pageCache中

2、每次要用代码调用值变更方法时,判断该值,从而避免二次调用

如图:

image.png

image.png


此方案实际上代码还是会走两遍,只不过不会再走第二次业务代码,从业务方面避免二次触发propertyChanged,也可以达到预期


疑问1:共享标识是否会引发线程安全问题?

经测试,苍穹插件,每次调用都是一个新的对象,所以PageCache对象也是一个新的,只有当前线程持有,是线程安全的

如图:

image.png

第一次调用的PageCache和第二次调用的PageCache是两个不一样的对象,线程安全!



疑问2:有评论说下面代码可以实现避免二次调用?

this.getModel().beginInit();

this.getModel().setValue();

this.getModel().endInit();


结论:经测试,没有用,还是会调用两次,如图:

1、界面原本是null,输入"f",第一次进入propertyChanged

2、然后执行业务代码,判断输入的"f"不是数字,设置null进入,此时第二次进入propertyChanged

3、第二次进入propertyChanged,可看到旧的值是"f",新的值是null

image.png

image.png

image.png


-- 2023/12/18 评论区@Reality 大佬的方法测试

DynamicObject data = this.getModel().getDataEntity(true);

DynamicObjectCollection entry = data.getDynamicObjectCollection("entryentity");

DynamicObject row = entry.get(rowIndex);

row.set("field",null);

this.getView().updateView("field",rowIndex);


结论:经测试,有用,不会触发二次propertyChanged

如图:

1、界面原本是null,输入"f",第一次进入propertyChanged

2、然后执行业务代码,判断输入的"f"不是数字,设置null,运行到set 和 updateView都没有再次进入propertyChanged

image.pngimage.png


跟了下源码

方法一:this.getModel().setValue(fieldKey, null, rowIndex);

方法二:DynamicObject row = entry.get(rowIndex);   row.set(fieldKey,null);

这两种方式走的代码都一样,都会执行到kd.bos.dataentity.metadata.dynamicobject.DynamicProperty#setValuePrivate

但是第一种会在执行setValuePrivate方法前,注册监听,并执行监听

PropertyChangeListener listener = this.registerPropChangeListener(currentRowObj, rowIndex, prop);

propertyChanged也是这个监听数组里面的一个元素

image.png


第二种就不会注册监听,所以每次在firePropertyChange时,获取不到监听数组,所以不会二次调用propertyChanged


第一种注册监听会获取到监听数组 named是有值的,会二次触发propertyChanged

image.png


第二种方式没有监听,named数组无值,不会二次触发propertyChanged

image.png



-- 2023/12/18 评论区@风 大佬的方法测试

this.getModel().initValue("field",null,rowIndex);

this.getView().updateView("field", rowIndex);


结论:经测试,也可以有用,不会触发二次propertyChanged,该方法也是目前来说最简便的,可首选

跟了源码,流程如下:

1、执行initValue方法

image.png


2、跟this.getModel().setValue(fieldKey, null, rowIndex);方式执行方式是一样的,也会注册监听,也会走监听

image.png


3、但是走到onPropertyChanged方法时,因为时init时刻设置值,所以isChange标识为false,所以不会执行OnPropertyChanged方法,所以避免了二次触发

image.png



如果谁还有更简便的方案,可以大家一起讨论~~~



赞 15