嵌套ListView无记录时禁用PopupWindowShowAction的问题
问题背景
嵌套ListView场景下,存在一个依赖当前选中记录执行逻辑的PopupWindowShowAction操作:无对应选中记录时执行该操作会抛出错误,因此需要在无有效当前记录时将操作置为禁用状态。
以下是初始编写的简化版控制器代码:
using DevExpress.ExpressApp; using DevExpress.ExpressApp.Actions; using DevExpress.ExpressApp.Editors; using System; using System.Linq; using System.Windows.Forms; namespace MyNamespace { public partial class JobWorkflowController : ViewController { PopupWindowShowAction actWorkflow; public JobWorkflowController() { TargetObjectType = typeof(IWorkflow); actWorkflow = new PopupWindowShowAction(this, "Workflow", "Admin") { AcceptButtonCaption = string.Empty, ActionMeaning = ActionMeaning.Accept, CancelButtonCaption = null, Caption = "Workflow", ConfirmationMessage = null, ImageName = "Workflow", Shortcut = "F7", ToolTip = null }; actWorkflow.CustomizePopupWindowParams += actWorkflow_CustomizePopupWindowParams_1; actWorkflow.Execute += actWorkflow_Execute_1; actWorkflow.Cancel += actWorkflow_Cancel; } private void actWorkflow_CustomizePopupWindowParams_1(object sender, CustomizePopupWindowParamsEventArgs e) { if (View.CurrentObject is not IWorkflow wf) { // 视图未初始化时执行到此处会触发错误 return; } // 弹窗视图创建逻辑 } private void actWorkflow_Execute_1(object sender, PopupWindowShowActionExecuteEventArgs e) { // 操作执行逻辑 } private void actWorkflow_Cancel(object sender, EventArgs e) { // 操作取消逻辑 } protected override void OnActivated() { base.OnActivated(); View.CurrentObjectChanged += View_CurrentObjectChanged; View_CurrentObjectChanged(View, new EventArgs()); } private void View_CurrentObjectChanged(object sender, EventArgs e) { actWorkflow.Enabled["HasCurrent"] = View.CurrentObject != null; } protected override void OnDeactivated() { View.CurrentObjectChanged -= View_CurrentObjectChanged; base.OnDeactivated(); } } }
目前已在OnActivated生命周期中订阅View.CurrentObjectChanged事件,在事件回调内通过设置actWorkflow.Enabled["HasCurrent"]属性值判断操作是否可用。经测试View_CurrentObjectChanged事件可正常触发,但操作并未按预期被禁用。
[更新]
尝试过Michael给出的建议方案,操作仍然无法正常禁用。
问题原因与修复方案
这个问题是嵌套ListView场景下的典型适配问题,核心原因有两点:
- 嵌套ListView(尤其是DetailView中通过ListPropertyEditor承载的嵌套列表)的选中状态变更,很多场景下只会触发
SelectionChanged事件,不会触发CurrentObjectChanged事件,仅订阅后者会漏过大量状态变更场景。 - 自定义Action的启用规则没有结合框架自带的选择依赖逻辑,状态更新后没有主动触发Action刷新,嵌套Frame中的Action状态不会自动同步到UI层。
按以下步骤修改即可解决:
- 给Action显式配置选择依赖类型,框架会自动接管大部分无选中、多选场景的禁用逻辑:
actWorkflow = new PopupWindowShowAction(this, "Workflow", "Admin") { // 保留原有初始化属性 SelectionDependencyType = SelectionDependencyType.RequireSingleObject };
- 补充事件订阅覆盖所有选中变更场景,处理视图延迟加载的初始状态问题,更新状态后主动刷新Action同步UI:
protected override void OnActivated() { base.OnActivated(); // 同时订阅两个事件,覆盖普通视图、嵌套列表的所有选中变更场景 View.CurrentObjectChanged += View_SelectedStateChanged; if(View is ListView lv) { lv.SelectionChanged += View_SelectedStateChanged; } // 视图未加载完成时,等加载完毕再初始化状态,避免初始状态显示错误 if(View.IsLoaded) { View_SelectedStateChanged(View, EventArgs.Empty); } else { EventHandler onLoad = null; onLoad = (s,e) => { View.Load -= onLoad; View_SelectedStateChanged(View, EventArgs.Empty); }; View.Load += onLoad; } } // 统一处理选中状态变更后的Action可用性更新 private void View_SelectedStateChanged(object sender, EventArgs e) { bool hasValidSelectedRecord = View.CurrentObject is IWorkflow; // ListView场景下通过SelectedObjects判断比CurrentObject更准确 if(View is ListView listView) { hasValidSelectedRecord = listView.SelectedObjects.Count == 1 && listView.SelectedObjects[0] is IWorkflow; } actWorkflow.Enabled["HasCurrent"] = hasValidSelectedRecord; // 主动刷新Action状态,解决嵌套Frame下UI不同步问题 actWorkflow.Refresh(); } protected override void OnDeactivated() { // 注销所有事件避免内存泄漏 View.CurrentObjectChanged -= View_SelectedStateChanged; if(View is ListView lv) { lv.SelectionChanged -= View_SelectedStateChanged; } base.OnDeactivated(); }
- 在弹窗参数自定义事件开头增加兜底校验,极端场景下状态同步延迟时也不会抛出底层错误:
private void actWorkflow_CustomizePopupWindowParams_1(object sender, CustomizePopupWindowParamsEventArgs e) { if (View.CurrentObject is not IWorkflow wf) { throw new UserFriendlyException("请先选中一条工作流记录后再执行操作"); } // 保留原有弹窗视图创建逻辑 }
内容的提问来源于stack exchange,提问作者Kirsten
相关产品推荐
相关产品推荐

