D365 FO执行进度显示
对于长时间执行的任务,D365 FO为了通知用户处理的进度,新增了一个进度条显示,如下图所示:
这个功能在AX2012及之前的版本是没有的,之前的版本是通过SysOperationProgress类来实现进度的显示,这个进度条跟界面的在一个线程,
所以用户点击界面是是没响应的。
D365 FO对于长时间操作启用进度显示集成到了SysOperation框架,当然Runbase框架也支持。
搞不懂为什么AX从2012版本开始就推出了SysOperation,并且推荐使用SysOperation替代RunBase,但是看上去还一直在维护RunBase框架,一些新的特性也加到了Runbase上,不知道是出于念旧还是遗留代码还没移植完。
实现方法
如果想显示进度条,只要覆盖canRunInNewSession,让它返回true就可以了。
具体的实例代码如下:
1 public class PersonController extends SysOperationServiceController 2 { 3 static void main(Args _args) 4 { 5 PersonController controller = new PersonController( 6 classStr(PersonController), 7 methodStr(PersonController, changeAge), 8 SysOperationExecutionMode::Synchronous); 9 10 controller.startOperation(); 11 } 12 13 public void changeAge(PersonDataContract _contract) 14 { 15 sleep(10000); 16 info (int2Str(_contract.parmAge())); 17 } 18 19 protected boolean canRunInNewSession() 20 { 21 return true; 22 } 23 24 public boolean canGoBatch() 25 { 26 return false; 27 } 28 29 public ClassDescription caption() 30 { 31 return "修改年龄"; 32 } 33 34 }
canGoBatch方法标识当前类是否支持批处理,我这里测试不想让它执行批处理,为了模仿长时间操作,用Sleep停止10S
为了简便起见,没有新创建Services类,正规的做法应该是在创建一个用于修改年龄的Services类供Controller调用,不过这样调用也没什么。
DataContract用于参数传递,定义如下。
[DataContract] public class PersonDataContract { int age; [DataMember,SysOperationLabel("年龄")] public int parmAge(int _age = age) { age = _age; return age; } }
执行上述方法就可以显示执行进度了。
实现原理
查看SysOperationServiceController的startOperation方法,不难发现这个进度条实现的原理。
是通过SysOperationSandboxForm这个Form实现的,在Form的init方法里调用了父类FormRun的runAsync方法,把要执行的任务放到另一个线程里执行。
至于显示的执行时间,是通过在窗体SysOperationSandboxForm上添加一个TimerControl控件实现的,具体实现可以查看类FormRun的addTimerForAsyncTaskPolling方法。