fix(legacy): complete hosted module cleanup

This commit is contained in:
2026-08-29 20:34:39 +08:00
parent 176952d52c
commit 9f5f548dea
15 changed files with 704 additions and 422 deletions
+262 -12
View File
@@ -292,6 +292,85 @@ namespace Lskj.PubBill
private void ReleaseModuleEvents()
{
// BillModule 会给来源、明细以及明细的明细动态创建的 GridView 注册
// 实例方法。DevExpress 的事件委托保存在 View 的 EventHandlerList 中,
// 即使 View 已经脱离 GridControl,也会继续强引用 BillModule。关闭时
// 只解除本模块注册的处理器,不 Dispose 共享的 GridControl/GridView。
List<System.Windows.Forms.Control> moduleControls = new List<System.Windows.Forms.Control>();
try
{
moduleControls.AddRange(EnumerateChildControls(this).ToList());
}
catch (Exception exception)
{
Debug.WriteLine("收集单据模块控件失败:" + exception);
}
// Form.Close/Dispose 期间某些页签可能已经从 Controls 移除,
// BillModuleModelDic 和页签 Tag 仍然保留这些动态控件的引用,
// 因此一并加入快照,确保解绑覆盖所有来源表格。
try
{
foreach (BillModuleModel moduleModel in BillModuleModelDic.Values.ToList())
{
AddModuleControlSnapshot(moduleControls, moduleModel == null ? null : moduleModel.SourceControl as System.Windows.Forms.Control);
AddModuleControlSnapshot(moduleControls, moduleModel == null ? null : moduleModel.SourceDetailControl as System.Windows.Forms.Control);
AddModuleControlSnapshot(moduleControls, moduleModel == null ? null : moduleModel.SourceDetailDetailControl as System.Windows.Forms.Control);
}
}
catch (Exception exception)
{
Debug.WriteLine("收集单据来源控件失败:" + exception);
}
foreach (System.Windows.Forms.Control control in moduleControls.ToList())
{
try
{
GridControlEx grid = control as GridControlEx;
if (grid != null)
ReleaseBillModuleGridEvents(grid);
TreeViewEx treeView = control as TreeViewEx;
if (treeView != null)
treeView.TreeNodeSelectAfter -= OnTreeNodeSelectAfter;
SplitContainerControl splitContainer = control as SplitContainerControl;
if (splitContainer != null)
{
splitContainer.SplitterMoved -= OnTopSplitterMoved;
splitContainer.SplitterMoved -= OnMainSplitterMoved;
splitContainer.SplitterMoved -= OnDetailsSplitterMoved;
splitContainer.SplitterMoved -= OnSpecialMainSplitterMoved;
splitContainer.SplitterMoved -= OnSpecialLeftSplitterMoved;
}
SimpleButton commonButton = control as SimpleButton;
if (commonButton != null)
commonButton.Click -= itemCommon_Click;
LabelImageEdit imageEdit = control as LabelImageEdit;
if (imageEdit != null)
{
imageEdit.UploadEvent -= OnImageUploadEvent;
imageEdit.DeleteEvent -= OnImageDeleteEvent;
}
}
catch (Exception exception)
{
Debug.WriteLine("解除单据模块控件事件失败:" + exception);
}
}
ReleaseBillModuleSearchEvents(moduleControls);
ReleaseBillModuleBarEvents();
if (_imageEdit != null)
{
_imageEdit.UploadEvent -= OnImageUploadEvent;
_imageEdit.DeleteEvent -= OnImageDeleteEvent;
}
if (ScanCodeTextEdit != null)
ScanCodeTextEdit.KeyDown -= Text_KeyDown;
@@ -299,18 +378,6 @@ namespace Lskj.PubBill
{
gcMain.OnAfterLinkCilk -= OnAfterLinkCilkCall;
gcMain.OnAllAfterParseCallBack -= OnAllAfterParseCallBack;
if (gcMain.GridControl != null)
gcMain.GridControl.DataSourceChanged -= OnGcMainDataSourceChanged;
if (gcMain.GridView != null)
{
gcMain.GridView.KeyDown -= OnToWithdraw;
gcMain.GridView.ShowingEditor -= OnGridViewShowingEditor;
gcMain.GridView.MouseDown -= GridView_MouseDown;
gcMain.GridView.FocusedRowChanged -= GridView_FocusedRowChanged;
gcMain.GridView.InitNewRow -= OnGridViewInitNewRow;
gcMain.GridView.CellValueChanged -= OnGridViewCellValueChanged;
gcMain.GridView.RowCellClick -= OngcMainRowCellClick;
}
}
if (tb_buttom != null)
@@ -323,6 +390,189 @@ namespace Lskj.PubBill
}
}
private static void AddModuleControlSnapshot(
List<System.Windows.Forms.Control> target,
System.Windows.Forms.Control control)
{
if (target == null || control == null)
return;
foreach (System.Windows.Forms.Control item in EnumerateChildControls(control))
{
if (!target.Contains(item))
target.Add(item);
}
}
private void ReleaseBillModuleGridEvents(GridControlEx grid)
{
if (grid == null)
return;
grid.OnAfterLinkCilk -= OnAfterLinkCilkCall;
grid.OnAllAfterParseCallBack -= OnAllAfterParseCallBack;
if (grid.GridControl != null)
{
grid.GridControl.DataSourceChanged -= OnGcMainDataSourceChanged;
grid.GridControl.ProcessGridKey -= OnGridControlKye;
}
GridView view = grid.GridView;
if (view != null)
{
view.DoubleClick -= OnGridViewDoubleClick;
view.DoubleClick -= OnSourceGridViewDoubleClick;
view.DoubleClick -= OnGridDetailDoubleClick;
view.DoubleClick -= OnGridDetailDetailDoubleClick;
view.RowCellClick -= OnGridViewRowCellClick;
view.RowCellClick -= OngcMainRowCellClick;
view.RowCellClick -= OnGridViewIsCheckClick;
view.FocusedRowObjectChanged -= GridView_FocusedRowObjectChanged;
view.FocusedRowChanged -= GridView_FocusedRowChanged;
view.KeyDown -= OnToWithdraw;
view.ShowingEditor -= OnGridViewShowingEditor;
view.MouseDown -= GridView_MouseDown;
view.InitNewRow -= OnGridViewInitNewRow;
view.CellValueChanged -= OnGridViewCellValueChanged;
view.CustomDrawCell -= GridView_CustomDrawCell;
}
TreeGridControlEx treeGrid = grid as TreeGridControlEx;
if (treeGrid != null && treeGrid.TreeListObj != null)
{
treeGrid.TreeListObj.FocusedNodeChanged -= OnTreeListObjFocusedNodeChanged;
treeGrid.TreeListObj.MouseClick -= TreeListObj_MouseClick;
treeGrid.TreeListObj.ShowingEditor -= OnGridViewShowingEditor;
}
if (grid.gridViewRightMenu != null)
{
grid.gridViewRightMenu.OnBeforeHandleParamsCallback -= OnBeforeHandleParamsCallback;
// SetGridRightMenus stores the module callback in the menu
// object (not on GridView), so clear only this menu's callback
// before the wrapper becomes unreachable.
grid.gridViewRightMenu.SetRightCallback(null);
}
}
private void ReleaseBillModuleSearchEvents(
IEnumerable<System.Windows.Forms.Control> moduleControls)
{
List<MyControl> searchControls = new List<MyControl>();
List<MyControl> ownedSearchControls = new List<MyControl>();
if (ControlObj != null)
{
searchControls.Add(ControlObj);
ownedSearchControls.Add(ControlObj);
}
try
{
IEnumerable<System.Windows.Forms.Control> controls = moduleControls == null
? EnumerateChildControls(this)
: moduleControls;
foreach (System.Windows.Forms.Control control in controls)
{
XtraTabPage page = control as XtraTabPage;
BillSourceUnionModel unionModel = page == null ? null : page.Tag as BillSourceUnionModel;
if (unionModel == null)
continue;
AddModuleSearchControl(searchControls, unionModel.SearchObj);
AddModuleSearchControl(ownedSearchControls, unionModel.SearchObj);
ModuleGridEx detailModule = unionModel.GridDetailModuleGridEx;
if (detailModule != null)
{
AddModuleSearchControl(searchControls, detailModule.SearchObj);
AddModuleSearchControl(ownedSearchControls, detailModule.SearchObj);
// ParentControlEx/ParentControlObj/_leftGridSearchObj can
// belong to another open module. They only need this
// module's callbacks removed; never Dispose them here.
AddModuleSearchControl(searchControls, detailModule.ParentControlEx);
AddModuleSearchControl(searchControls, detailModule.ParentControlObj);
AddModuleSearchControl(searchControls, detailModule._leftGridSearchObj);
}
}
}
catch (Exception exception)
{
Debug.WriteLine("收集单据查询控件失败:" + exception);
}
foreach (MyControl searchControl in searchControls.ToList())
{
if (searchControl == null)
continue;
try
{
searchControl.OnSearchBeforeCallBack -= OnSearchBefore;
searchControl.OnSearchAfterCallBack -= OnSearchAfterd;
searchControl.OnDataSourceBindCallBack -= OnFirstPageDataSourceBindCallBack;
searchControl.OnDataSourceBindCallBack -= SearchControl_OnDataSourceBindCallBack;
searchControl.OnDataSourceBindCallBack -= OnPageDataSourceBindCallBack;
searchControl.OpenDocumentSource -= OpenTheSourcePopup;
searchControl.OnSourceRefrshCallBack -= OnRefreshBillSource;
searchControl.OnDataFileRefrshCallBack -= OnDataFileRefrshFile;
searchControl.OnDataSourceBindCallBack -= OnInitializeHeaderCallBack;
}
catch (Exception exception)
{
Debug.WriteLine("解除单据查询事件失败:" + exception);
}
}
// MyControl 不是 WinForms Control,不会随页签自动进入 Dispose
// 链。它内部可能持有 WinForms Timer、弹出菜单和查询控件引用;
// 只释放本模块创建的对象,外部传入的父级查询控件保持不动。
foreach (MyControl searchControl in ownedSearchControls.ToList())
{
try
{
searchControl.Dispose();
}
catch (Exception exception)
{
Debug.WriteLine("释放单据查询控件失败:" + exception);
}
}
}
private static void AddModuleSearchControl(List<MyControl> target, MyControl control)
{
if (target != null && control != null && !target.Contains(control))
target.Add(control);
}
private void ReleaseBillModuleBarEvents()
{
if (itemCommonList != null)
{
foreach (SimpleButton button in itemCommonList.ToList())
if (button != null)
button.Click -= itemCommon_Click;
}
if (barManager1 == null || barManager1.Items == null)
return;
foreach (BarItem item in barManager1.Items)
{
BarButtonItem button = item as BarButtonItem;
if (button == null)
continue;
button.ItemClick -= OnCopyMasterItemClick;
button.ItemClick -= OnCopyAllItemClick;
button.ItemClick -= OnExportItemClick;
button.ItemClick -= OnBtnFPNewClick;
button.ItemClick -= OnImportItemClick;
button.ItemClick -= OnImportUpdateItemClick;
button.ItemClick -= OnPrintItemClick;
button.ItemClick -= OnCommonItemClick;
}
}
private void ReleaseModuleDataSources()
{
foreach (System.Windows.Forms.Control control in EnumerateChildControls(this).ToList())