如何模拟MSP的Application.ProjectAfterClose事件维护ComboBox项目列表?
解决MSP项目关闭时ComboBox列表更新的最后一个项目检测问题
问题背景
我需要让ComboBox始终同步显示所有已打开的MSP项目,要求在项目打开、关闭时实时更新列表。目前项目打开的逻辑已经实现,但关闭环节存在两个核心问题:
- 仅用
ProjectBeforeCloseEvent会在保存弹窗弹出前触发,用户可能取消关闭操作,导致列表误更新 - 用
ProjectBeforeCloseEvent+WindowActivateEvent的临时方案,无法检测用户取消关闭最后一个项目的场景(此时没有新窗口激活,WindowActivateEvent不会触发) - 不想用定时器轮询的方式来检测项目状态
已经优化代码避免了未关闭项目却误删列表项的问题,但最后一个项目关闭的检测这个核心问题仍未解决。
现有实现代码
private void _prjApp_WindowActivateEvent(MSP.Window activatedWindow) { List<string> prjFileNames = ReturnOpenProjFileNames(); if (projectOpened) { foreach (var prjName in prjFileNames) { if (cbMSP.Items.Contains(prjName) == false) { AddMSPToComboBox(prjName); } } } if (projectClosed) { for (int i = cbMSP.Items.Count - 1; i >= 0; i--) { string prjName = cbMSP.Items[i].ToString(); if (prjFileNames.Contains(prjName) == false) { DeleteMSPInComboBox(prjName); } } } projectClosed = false; projectOpened = false; }
注:用projectOpened和projectClosed两个布尔变量关联ProjectBeforeCloseEvent和NewProjectEvent,减少切换活动项目时的不必要代码执行。
解决方案
核心思路
通过记录待关闭项目的临时标记,结合MSP的ProjectAfterSave和Quit事件,精准判断项目是否真的被关闭,覆盖所有场景包括最后一个项目的处理。
具体实现步骤
- 新增全局变量记录待关闭的项目名称
private string _pendingCloseProject;
- 修改
ProjectBeforeCloseEvent,只记录待关闭项目,不直接更新列表
private void _prjApp_ProjectBeforeCloseEvent(MSP.Project p, ref bool Cancel) { _pendingCloseProject = p.Name; // 暂存待关闭的项目名 }
- 监听
ProjectAfterSave事件,确认项目是否真的关闭
private void _prjApp_ProjectAfterSaveEvent(MSP.Project p) { if (!string.IsNullOrEmpty(_pendingCloseProject)) { List<string> currentOpenProjects = ReturnOpenProjFileNames(); // 检查待关闭项目是否还在打开列表里,不在就更新ComboBox if (!currentOpenProjects.Contains(_pendingCloseProject)) { DeleteMSPInComboBox(_pendingCloseProject); _pendingCloseProject = null; } } }
- 监听
Application.Quit事件,处理最后一个项目关闭导致MSP退出的场景
private void _prjApp_QuitEvent() { cbMSP.Items.Clear(); _pendingCloseProject = null; }
- 优化
WindowActivateEvent,补充待关闭项目的状态检查
在原有逻辑基础上,增加以下代码:
// 检查是否有待关闭的项目需要验证状态 if (!string.IsNullOrEmpty(_pendingCloseProject)) { List<string> currentOpen = ReturnOpenProjFileNames(); if (!currentOpen.Contains(_pendingCloseProject)) { DeleteMSPInComboBox(_pendingCloseProject); _pendingCloseProject = null; } else { // 用户取消了关闭操作,清空待关闭标记 _pendingCloseProject = null; } }
方案优势
- 不需要定时器轮询,完全通过MSP原生事件驱动
- 覆盖所有关闭场景:用户正常关闭、取消关闭、最后一个项目关闭退出
- 避免了
ProjectBeforeCloseEvent触发过早导致的误更新问题
内容的提问来源于stack exchange,提问作者James Cloud
相关产品推荐
相关产品推荐

