3 Commits

Author SHA1 Message Date
tdx 7d8ad77f5c merge: 合并初始化缓存与资源释放优化 2026-08-15 11:39:58 +08:00
tdx f72b153eb6 fix(pubbill): 恢复主表格界面布局 2026-08-15 10:30:58 +08:00
tdx c49015d390 fix: 收敛旧模块资源释放与诊断 2026-08-15 10:13:08 +08:00
59 changed files with 4220 additions and 429 deletions
@@ -13,9 +13,13 @@
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
if (disposing)
{
components.Dispose();
ReleaseResourcesForDispose();
if (components != null)
{
components.Dispose();
}
}
base.Dispose(disposing);
}
@@ -666,4 +670,4 @@
private Control.TabControlEx tab_basicInfo;
private DevExpress.XtraEditors.DropDownButton btnPrint;
}
}
}
@@ -64,6 +64,7 @@ namespace Lskj.BaseAccraditation
/// 主表控件
/// </summary>
public MyControl ControlObj;
private bool mResourcesReleased;
#endregion
@@ -191,6 +192,42 @@ namespace Lskj.BaseAccraditation
InitializeComponent();
}
private void ReleaseResourcesForDispose()
{
if (mResourcesReleased)
{
return;
}
mResourcesReleased = true;
PrintUtil.OnAfterPrint -= OnReportPrintAfter;
MyControl control = ControlObj;
ControlObj = null;
if (control != null)
{
control.OnDataSourceBindCallBack -=
OnControlObjOnDataSourceBindCallBack;
control.Dispose();
}
try
{
if (tab_basicInfo != null)
{
tab_basicInfo.ParentControlEx = null;
}
if (SysModel != null && SysModel.DataCaches != null)
{
SysModel.DataCaches.Remove(this);
}
}
catch
{
// A partially disposed child must not stop form cleanup.
}
}
public override void SetFormSize()
{
this.WindowState = FormWindowState.Normal;
+7 -2
View File
@@ -13,9 +13,14 @@
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
if (disposing)
{
components.Dispose();
Lskj.Control.Model.PrintUtil.OnAfterPrint -=
new System.EventHandler(OnReportPrintAfter);
if (components != null)
{
components.Dispose();
}
}
base.Dispose(disposing);
}
+6 -2
View File
@@ -13,9 +13,13 @@
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
if (disposing)
{
components.Dispose();
ReleaseResourcesForDispose();
if (components != null)
{
components.Dispose();
}
}
base.Dispose(disposing);
}
+76 -16
View File
@@ -41,11 +41,79 @@ namespace Lskj.Control
{
public partial class AuditPanelEx : UserControl
{
private bool mResourcesReleased;
public AuditPanelEx()
{
InitializeComponent();
}
internal void ReleaseResourcesForDispose()
{
if (mResourcesReleased)
{
return;
}
mResourcesReleased = true;
MyControl searchControl = _searchContrl;
_searchContrl = null;
if (searchControl != null)
{
searchControl.Dispose();
}
try
{
if (gridFinish != null && gridFinish.GridView != null)
{
gridFinish.GridView.SelectionChanged -= GvFinish_SelectionChangedClick;
gridFinish.GridView.DoubleClick -= GvFinish_DoubleClick;
}
foreach (TabPageObj tabPage in _tabPageObjs)
{
foreach (TabPageItemObj item in tabPage.TabPageItemObjs)
{
if (item.GridControlObj != null &&
item.GridControlObj.GridView != null)
{
item.GridControlObj.GridView.DoubleClick -=
OnGridViewDoubleClick;
item.GridControlObj.Model = null;
}
}
tabPage.TabPageItemObjs.Clear();
}
}
catch
{
// A partially disposed DevExpress view must not stop cleanup.
}
try
{
if (SysModel != null && SysModel.DataCaches != null)
{
SysModel.DataCaches.Remove(this);
}
}
catch
{
// Cache cleanup must not interrupt control disposal.
}
_tabPageObjs.Clear();
_tabPageCount.Clear();
OnGridViewDoubleCallBack = null;
OnGridFinshViewDoubleCallBack = null;
OnBtnSearchCallBack = null;
SectionAccradit = null;
AuditComModelObj = null;
BaseAccraditModelObj = null;
PubSysModel = null;
SysModel = null;
}
#region
/// <summary>
@@ -299,17 +367,12 @@ namespace Lskj.Control
{
return new AccraditationModel(dataRow);
}));
Task<GridControlEx> gridControlExTask = cachesDic.AddTask(dataRow, "GridControlEx", new Task<GridControlEx>(() =>
{
return new GridControlEx();
}));
GridControlEx gridControlEx = gridControlExTask.Result;
string key = "FLOWSTEP_" + dynamicModel.ModuleCode + "_" + flowTypeStepModelTask.Result.StepCode + "_" + accraditationModelTask.Result.Id + "";
Task<DataTable> baseGridRowColorsTask = cachesDic.AddTask(gridControlEx, "BaseGridRowColors", new Task<DataTable>(() =>
Task<DataTable> baseGridRowColorsTask = cachesDic.AddTask(dataRow, "BaseGridRowColors", new Task<DataTable>(() =>
{
return BaseModuleImpl.GetBaseGridRowColors(key);
}));
Task<DataTable> flowstepGridRightMenusTask = cachesDic.AddTask(gridControlEx, "FlowstepGridRightMenus", new Task<DataTable>(() =>
Task<DataTable> flowstepGridRightMenusTask = cachesDic.AddTask(dataRow, "FlowstepGridRightMenus", new Task<DataTable>(() =>
{
return BaseModuleImpl.GetBaseGridRightMenus($"FLOWSTEP_{accraditationModelTask.Result.Formkey}");
}));
@@ -317,10 +380,6 @@ namespace Lskj.Control
//{
// return BaseImpl.GetDataTableResult(accraditationModelTask.Result.StepSql);
//}));
string modelkeyName = isBill ? GridCustomColumnStruct.AuditMainGridView : GridCustomColumnStruct.BaseAuditMainGridView;
string customColumKey = modelkeyName + key;
cachesDic.AddTask(gridControlEx, "DynamicModel", dynamicModelTask);
gridControlEx.GetDataCaches(cachesDic, customColumKey);
}
return flowList;
}));
@@ -613,18 +672,19 @@ namespace Lskj.Control
gridPanel.Padding = new System.Windows.Forms.Padding(2);
gridPanel.Dock = DockStyle.Right;
gridPanel.BorderStyle = BorderStyles.NoBorder;
if (!dataCaches.GetValue(dataRow, "GridControlEx", out GridControlEx grid))
GridControlEx grid = new GridControlEx();
if (dataCaches != null)
{
grid = new GridControlEx();
grid.GetDataCaches(dataCaches, modelkeyName + key);
}
grid.Parent = gridPanel;
grid.Dock = DockStyle.Fill;
grid.BorderStyle = BorderStyle.None;
if (!dataCaches.GetValue(grid, "BaseGridRowColors", out DataTable dtGridRowColors))
if (!dataCaches.GetValue(dataRow, "BaseGridRowColors", out DataTable dtGridRowColors))
{
dtGridRowColors = BaseModuleImpl.GetBaseGridRowColors(key);
}
if (!dataCaches.GetValue(grid, "FlowstepGridRightMenus", out DataTable dtGridRightMenus))
if (!dataCaches.GetValue(dataRow, "FlowstepGridRightMenus", out DataTable dtGridRightMenus))
{
dtGridRightMenus = BaseModuleImpl.GetBaseGridRightMenus($"FLOWSTEP_{accrModel.Formkey}");
}
@@ -1906,4 +1966,4 @@ namespace Lskj.Control
}
}
}
}
+111 -62
View File
@@ -78,17 +78,17 @@ namespace Lskj.Control.BrowserSetting
string arg2 = message.Arguments.GetString(2);
string arg3 = message.Arguments.GetString(3);
string arg4 = message.Arguments.GetString(4);
if (ERPInfo.Instance.MainControl.InvokeRequired)
{
ERPInfo.Instance.MainControl.Invoke(new Action(() =>
PostToUiThread(
ERPInfo.Instance.MainControl,
delegate
{
BsOpenModuleHandler.OpenModule(arg0, arg1, arg2, arg3, arg4);
}));
}
else
{
BrowserSetting.BsOpenModuleHandler.OpenModule(arg0, arg1, arg2, arg3, arg4);
}
BsOpenModuleHandler.OpenModule(
arg0,
arg1,
arg2,
arg3,
arg4);
});
}
else if (message.Name.Equals("OpenOnRightClick"))
{
@@ -96,75 +96,103 @@ namespace Lskj.Control.BrowserSetting
string arg1 = message.Arguments.GetString(1);
string arg2 = message.Arguments.GetString(2);
string arg3 = message.Arguments.GetString(3);
if (ERPInfo.Instance.MainControl.InvokeRequired)
{
ERPInfo.Instance.MainControl.Invoke(new Action(() =>
PostToUiThread(
ERPInfo.Instance.MainControl,
delegate
{
BsOpenModuleHandler.OpenRightModule(arg0, arg1, arg2, arg3);
}));
}
else
{
BsOpenModuleHandler.OpenRightModule(arg0, arg1, arg2, arg3);
}
BsOpenModuleHandler.OpenRightModule(
arg0,
arg1,
arg2,
arg3);
});
}
else if (message.Name.Equals("CloseWin"))
{
if (frmWebBrowser != null && frmWebBrowser.Parent != null && frmWebBrowser.Parent.Parent != null && frmWebBrowser.Parent.Parent is BaseForm baseForm)
{
if (baseForm.InvokeRequired)
{
baseForm.Invoke(new Action(() =>
{
baseForm.DialogResult = DialogResult.OK;
baseForm.Close();
}));
}
else
var browserControl = frmWebBrowser;
PostToUiThread(
browserControl,
delegate
{
// Parent/Parent is a WinForms control-tree read and must
// not run on CEF's UI thread.
var parent = browserControl.Parent;
var baseForm = parent == null
? null
: parent.Parent as BaseForm;
if (baseForm == null || baseForm.IsDisposed)
return;
baseForm.DialogResult = DialogResult.OK;
baseForm.Close();
}
}
});
}
else if (message.Name.Equals("SelectPro"))
{
string arg0 = message.Arguments.GetString(0);
string arg1 = message.Arguments.GetString(1);
bool isclose = arg1!=null&&!string.IsNullOrWhiteSpace(arg1) && arg1.Equals("1") ? true : false;
if (frmWebBrowser != null && frmWebBrowser.Parent != null && frmWebBrowser.Parent.Parent != null && frmWebBrowser.Parent.Parent is BaseForm baseForm)
{
if (baseForm.InvokeRequired)
{
baseForm.Invoke(new Action(() =>
{
BsOpenModuleHandler.AddReturnRow(arg0);
if (isclose)
{
baseForm.DialogResult = DialogResult.OK;
baseForm.Close();
}
}));
}
else
var browserControl = frmWebBrowser;
PostToUiThread(
browserControl,
delegate
{
var parent = browserControl.Parent;
var baseForm = parent == null
? null
: parent.Parent as BaseForm;
if (baseForm == null || baseForm.IsDisposed)
return;
BsOpenModuleHandler.AddReturnRow(arg0);
if (isclose)
if (isclose)
{
baseForm.DialogResult = DialogResult.OK;
baseForm.Close();
}
}
}
}
});
}
return base.OnProcessMessageReceived(browser, frame, sourceProcess, message);
}
private static void PostToUiThread(
System.Windows.Forms.Control control,
Action action)
{
if (control == null || action == null || control.IsDisposed ||
!control.IsHandleCreated)
return;
Action guardedAction = delegate
{
if (control.IsDisposed)
return;
try
{
action();
}
catch (Exception exception)
{
ReportProcessMessageFailure(exception);
}
};
try
{
// CEF invokes OnProcessMessageReceived on its UI thread. A
// synchronous Control.Invoke can block that thread inside a
// modal dialog while the dialog waits for CEF to create its
// browser. Always queue the operation and return to CEF first.
control.BeginInvoke(guardedAction);
}
catch (Exception exception)
{
ReportProcessMessageFailure(exception);
}
}
private static void ReportProcessMessageFailure(Exception exception)
{
try
@@ -173,10 +201,10 @@ namespace Lskj.Control.BrowserSetting
}
catch
{
// Logging must never rethrow across the native CEF callback.
// Never propagate logging failures into a native CEF callback.
}
Action showError = () =>
Action showError = delegate
{
try
{
@@ -184,14 +212,14 @@ namespace Lskj.Control.BrowserSetting
}
catch
{
// Error reporting must never terminate the browser callback.
}
};
try
{
System.Windows.Forms.Control mainControl = ERPInfo.Instance.MainControl;
if (mainControl == null || mainControl.IsDisposed || !mainControl.IsHandleCreated)
if (mainControl == null || mainControl.IsDisposed ||
!mainControl.IsHandleCreated)
return;
if (mainControl.InvokeRequired)
@@ -201,15 +229,36 @@ namespace Lskj.Control.BrowserSetting
}
catch
{
// The main window may close while the CEF callback is reporting.
// The main window may close while the callback is reporting.
}
}
public void Created(CefBrowser cefBrowser)
{
if (OnCreated != null)
if (frmWebBrowser != null && OnCreated != null)
{
OnCreated(cefBrowser, EventArgs.Empty);
}
}
public bool Closing(CefBrowser browser)
{
var control = frmWebBrowser;
return control != null && control.BrowserClosing(browser);
}
public void Closed(CefBrowser browser)
{
var control = frmWebBrowser;
if (control != null)
{
control.BrowserClosed(browser);
if (control.cefBrowserSettings == null)
{
frmWebBrowser = null;
OnCreated = null;
}
}
}
}
}
@@ -42,7 +42,7 @@ namespace Lskj.Control.BrowserSetting
}
if (BsClient != null && BsClient.frmWebBrowser != null && BsClient.frmWebBrowser.Parent != null && BsClient.frmWebBrowser.Parent.Name.Equals("previewFrm"))
{
browser.GetHost().CloseBrowser();
BsClient.frmWebBrowser.CloseBrowser();
}
else if (BsClient != null && BsClient.frmWebBrowser != null)
{
@@ -196,11 +196,24 @@ namespace Lskj.Control.BrowserSetting
try
{
if (browser == null) return null;
IntPtr browserHandle = browser.GetHost().GetWindowHandle();
IntPtr browserHandle;
using (var browserHost = browser.GetHost())
{
browserHandle = browserHost.GetWindowHandle();
}
if (browserHandle == IntPtr.Zero) return null;
IntPtr parentHandle = GetParent(browserHandle);
if (parentHandle == IntPtr.Zero) return null;
System.Windows.Forms.Control control = System.Windows.Forms.Control.FromHandle(parentHandle);
System.Windows.Forms.Control control = null;
while (parentHandle != IntPtr.Zero && control == null)
{
// The CEF child now sits inside an application-owned native
// host. Walk through that host to preserve the original
// FrmWebBrowser-based module lookup.
control = System.Windows.Forms.Control.FromHandle(parentHandle);
parentHandle = GetParent(parentHandle);
}
if (control == null) return null;
if (control != null && control.Parent != null && control.Parent.Parent != null)
{
@@ -20,9 +20,20 @@ namespace Lskj.Control.BrowserSetting
base.OnAfterCreated(browser);
BsClient.Created(browser);
}
protected override bool DoClose(CefBrowser browser)
{
// CEF sends WM_CLOSE to the parked application-owned host after
// this callback. The host only allows that second close attempt.
return BsClient.Closing(browser);
}
protected override void OnBeforeClose(CefBrowser browser)
{
base.OnBeforeClose(browser);
// Release owner references after CEF completes its async close.
BsClient.Closed(browser);
}
protected override bool OnBeforePopup(
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using Xilium.CefGlue;
using Lskj.Business;
namespace Lskj.Control.BrowserSetting
{
@@ -46,7 +47,12 @@ namespace Lskj.Control.BrowserSetting
protected override void OnRenderProcessTerminated(CefBrowser browser, CefTerminationStatus status)
{
browser.Reload();
// Reloading immediately from this callback can create a new
// renderer while the old one is tearing down and cause a native
// libcef crash loop. Record the termination and let the module
// lifecycle decide whether a later reopen is appropriate.
LogUtil.WriteError("CEF 渲染进程已终止,状态=" + status,
new InvalidOperationException("CEF renderer termination status=" + status));
}
}
@@ -1,5 +1,6 @@
using Lskj.Business;
using Lskj.Model;
using Lskj.Util;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -54,6 +55,19 @@ namespace Lskj.Control.BrowserSetting2
return contextMenuHandler;
}
protected override bool OnProcessMessageReceived(CefBrowser browser, CefFrame frame, CefProcessId sourceProcess, CefProcessMessage message)
{
try
{
return OnProcessMessageReceivedCore(browser, frame, sourceProcess, message);
}
catch (Exception exception)
{
ReportProcessMessageFailure(exception);
return true;
}
}
private bool OnProcessMessageReceivedCore(CefBrowser browser, CefFrame frame, CefProcessId sourceProcess, CefProcessMessage message)
{
if (message.Name.Equals("OpenModule"))
{
@@ -62,17 +76,17 @@ namespace Lskj.Control.BrowserSetting2
string arg2 = message.Arguments.GetString(2);
string arg3 = message.Arguments.GetString(3);
string arg4 = message.Arguments.GetString(4);
if (ERPInfo.Instance.MainControl.InvokeRequired)
{
ERPInfo.Instance.MainControl.Invoke(new Action(() =>
PostToUiThread(
ERPInfo.Instance.MainControl,
delegate
{
BrowserSetting.BsOpenModuleHandler.OpenModule(arg0, arg1, arg2, arg3, arg4);
}));
}
else
{
BrowserSetting.BsOpenModuleHandler.OpenModule(arg0, arg1, arg2, arg3, arg4);
}
BrowserSetting.BsOpenModuleHandler.OpenModule(
arg0,
arg1,
arg2,
arg3,
arg4);
});
}
else if (message.Name.Equals("OpenOnRightClick"))
{
@@ -80,43 +94,140 @@ namespace Lskj.Control.BrowserSetting2
string arg1 = message.Arguments.GetString(1);
string arg2 = message.Arguments.GetString(2);
string arg3 = message.Arguments.GetString(3);
if (ERPInfo.Instance.MainControl.InvokeRequired)
{
ERPInfo.Instance.MainControl.Invoke(new Action(() =>
PostToUiThread(
ERPInfo.Instance.MainControl,
delegate
{
BrowserSetting.BsOpenModuleHandler.OpenRightModule(arg0, arg1, arg2, arg3);
}));
}
else
{
BrowserSetting.BsOpenModuleHandler.OpenRightModule(arg0, arg1, arg2, arg3);
}
BrowserSetting.BsOpenModuleHandler.OpenRightModule(
arg0,
arg1,
arg2,
arg3);
});
}
else if (message.Name.Equals("CloseWin"))
{
if (frmWebBrowser != null && frmWebBrowser.Parent != null && frmWebBrowser.Parent.Parent != null && frmWebBrowser.Parent.Parent is BaseForm baseForm)
{
if (baseForm.InvokeRequired)
{
baseForm.Invoke(new Action(() =>
{
baseForm.Close();
}));
}
else
var browserControl = frmWebBrowser;
PostToUiThread(
browserControl,
delegate
{
// Resolve the owning form only after returning to the
// WinForms UI thread.
var parent = browserControl.Parent;
var baseForm = parent == null
? null
: parent.Parent as BaseForm;
if (baseForm == null || baseForm.IsDisposed)
return;
baseForm.Close();
}
}
});
}
return base.OnProcessMessageReceived(browser, frame, sourceProcess, message);
}
private static void PostToUiThread(
System.Windows.Forms.Control control,
Action action)
{
if (control == null || action == null || control.IsDisposed ||
!control.IsHandleCreated)
return;
Action guardedAction = delegate
{
if (control.IsDisposed)
return;
try
{
action();
}
catch (Exception exception)
{
ReportProcessMessageFailure(exception);
}
};
try
{
// Never keep CEF's UI thread blocked while WinForms opens a
// modal module that may create another CEF browser.
control.BeginInvoke(guardedAction);
}
catch (Exception exception)
{
ReportProcessMessageFailure(exception);
}
}
private static void ReportProcessMessageFailure(Exception exception)
{
try
{
LogHelper.Instance.WriteError(exception);
}
catch
{
// Never propagate logging failures into a native CEF callback.
}
Action showError = delegate
{
try
{
MessageUtil.Show(exception);
}
catch
{
}
};
try
{
System.Windows.Forms.Control mainControl = ERPInfo.Instance.MainControl;
if (mainControl == null || mainControl.IsDisposed ||
!mainControl.IsHandleCreated)
return;
if (mainControl.InvokeRequired)
mainControl.BeginInvoke(showError);
else
showError();
}
catch
{
// The main window may close while the callback is reporting.
}
}
public void Created(CefBrowser cefBrowser)
{
if (OnCreated != null)
if (frmWebBrowser != null && OnCreated != null)
{
OnCreated(cefBrowser, EventArgs.Empty);
}
}
public bool Closing(CefBrowser browser)
{
var control = frmWebBrowser;
return control != null && control.BrowserClosing(browser);
}
public void Closed(CefBrowser browser)
{
var control = frmWebBrowser;
if (control != null)
{
control.BrowserClosed(browser);
if (control.cefBrowserSettings == null)
{
frmWebBrowser = null;
OnCreated = null;
}
}
}
}
}
@@ -20,9 +20,20 @@ namespace Lskj.Control.BrowserSetting2
base.OnAfterCreated(browser);
BsClient.Created(browser);
}
protected override bool DoClose(CefBrowser browser)
{
// CEF sends WM_CLOSE to the parked application-owned host after
// this callback. The host only allows that second close attempt.
return BsClient.Closing(browser);
}
protected override void OnBeforeClose(CefBrowser browser)
{
base.OnBeforeClose(browser);
// Release owner references after CEF completes its async close.
BsClient.Closed(browser);
}
protected override bool OnBeforePopup(
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using Xilium.CefGlue;
using Lskj.Business;
namespace Lskj.Control.BrowserSetting2
{
@@ -46,7 +47,9 @@ namespace Lskj.Control.BrowserSetting2
protected override void OnRenderProcessTerminated(CefBrowser browser, CefTerminationStatus status)
{
browser.Reload();
// Do not start a new renderer during native teardown.
LogUtil.WriteError("CEF 渲染进程已终止,状态=" + status,
new InvalidOperationException("CEF renderer termination status=" + status));
}
}
File diff suppressed because it is too large Load Diff
+2
View File
@@ -14,6 +14,8 @@ namespace Lskj.Control
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing)
CloseBrowserForDispose();
if (disposing && (components != null))
{
components.Dispose();
+39
View File
@@ -109,6 +109,45 @@ namespace Lskj.Control
cefBrowserSettings.GetMainFrame().LoadUrl(webResponse.ResponseUri.AbsoluteUri);
}
}
internal bool BrowserClosing(CefBrowser browser)
{
return false;
}
internal void BrowserClosed(CefBrowser browser)
{
var currentBrowser = cefBrowserSettings;
if (currentBrowser == null || browser == null)
return;
bool sameBrowser = ReferenceEquals(currentBrowser, browser);
if (!sameBrowser)
{
try
{
sameBrowser = currentBrowser.IsSame(browser);
}
catch (Exception)
{
}
}
if (sameBrowser)
Interlocked.CompareExchange(ref cefBrowserSettings, null, currentBrowser);
}
internal void CloseBrowser()
{
var browser = cefBrowserSettings;
if (browser != null)
browser.GetHost().CloseBrowser();
}
private void CloseBrowserForDispose()
{
}
public static string ToEnUrl(string url)
{
string[] urlParams = url.Split('?');
+2
View File
@@ -14,6 +14,8 @@ namespace Lskj.Control
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing)
CloseBrowserForDispose();
if (disposing && (components != null))
{
components.Dispose();
+39
View File
@@ -126,6 +126,45 @@ namespace Lskj.Control
cefBrowserSettings.GetMainFrame().LoadUrl(webResponse.ResponseUri.AbsoluteUri);
}
}
internal bool BrowserClosing(CefBrowser browser)
{
return false;
}
internal void BrowserClosed(CefBrowser browser)
{
var currentBrowser = cefBrowserSettings;
if (currentBrowser == null || browser == null)
return;
bool sameBrowser = ReferenceEquals(currentBrowser, browser);
if (!sameBrowser)
{
try
{
sameBrowser = currentBrowser.IsSame(browser);
}
catch (Exception)
{
}
}
if (sameBrowser)
Interlocked.CompareExchange(ref cefBrowserSettings, null, currentBrowser);
}
internal void CloseBrowser()
{
var browser = cefBrowserSettings;
if (browser != null)
browser.GetHost().CloseBrowser();
}
private void CloseBrowserForDispose()
{
}
public static string ToEnUrl(string url)
{
string[] urlParams = url.Split('?');
@@ -47,6 +47,7 @@ namespace Lskj.Control
private bool mExtendedReturnDisplayEventAttached;
private bool mExtendedReturnEditEventAttached;
private bool mExtendedReturnDisposeEventAttached;
private volatile bool mExtendedReturnDisposed;
private int mExtendedReturnSchemaGeneration;
private sealed class ExtendedLookupRequestState
@@ -62,6 +63,9 @@ namespace Lskj.Control
{
public GridColumnModel Model;
public ExtendedReturnSearchPopup Popup;
public PopupContainerControl PopupControl;
public RepositoryItemPopupContainerEdit SearchEdit;
public RepositoryItemTextEdit DisplayEdit;
public PopupContainerEdit OwnerEdit;
public DataRow BusinessRow;
}
@@ -124,7 +128,7 @@ namespace Lskj.Control
private void GridControlEx_Disposed_ExtendedReturn(object sender, EventArgs e)
{
DisposeExtendedReturnRequestTimers();
DisposeExtendedReturnResources();
}
private void InitExtendedSearchReturn(GridColumn column, GridColumnModel model)
@@ -138,6 +142,8 @@ namespace Lskj.Control
column.ColumnEdit = displayEdit;
column.FilterMode = ColumnFilterMode.DisplayText;
mExtendedReturnSearchEditors[model.FieldName] = searchEdit;
ExtendedReturnPopupContext context = GetExtendedReturnPopupContext(model.FieldName);
context.DisplayEdit = displayEdit;
this.mControlList.Add(model);
if (!mExtendedReturnEditEventAttached)
@@ -150,6 +156,14 @@ namespace Lskj.Control
private RepositoryItemPopupContainerEdit CreateExtendedReturnSearchEdit(GridColumnModel model)
{
ExtendedReturnPopupContext previousContext;
if (mExtendedReturnPopupContexts.TryGetValue(model.FieldName, out previousContext))
{
mExtendedReturnPopupContexts.Remove(model.FieldName);
mExtendedReturnSearchEditors.Remove(model.FieldName);
DisposeExtendedReturnPopupContext(previousContext);
}
Size popupSize = GetExtendedReturnPopupSize(model);
ExtendedReturnSearchPopup popup = new ExtendedReturnSearchPopup();
popup.Dock = DockStyle.Fill;
@@ -185,7 +199,9 @@ namespace Lskj.Control
ExtendedReturnPopupContext context = new ExtendedReturnPopupContext
{
Model = model,
Popup = popup
Popup = popup,
PopupControl = popupControl,
SearchEdit = searchEdit
};
popupControl.Tag = context;
popup.Tag = context;
@@ -662,6 +678,8 @@ namespace Lskj.Control
string searchField,
bool schemaOnly)
{
if (mExtendedReturnDisposed) return;
GridColumnModel model = context.Model;
ExtendedLookupRequest request;
lock (mExtendedReturnSyncRoot)
@@ -713,6 +731,8 @@ namespace Lskj.Control
private void ExtendedReturnDebounceElapsed(object stateValue)
{
if (mExtendedReturnDisposed) return;
string fieldName = stateValue as string;
if (string.IsNullOrWhiteSpace(fieldName)) return;
@@ -723,6 +743,8 @@ namespace Lskj.Control
private void StartExtendedReturnWorker(string fieldName)
{
if (mExtendedReturnDisposed) return;
ExtendedLookupRequest request;
lock (mExtendedReturnSyncRoot)
{
@@ -750,6 +772,8 @@ namespace Lskj.Control
{
while (request != null)
{
if (mExtendedReturnDisposed) return;
lock (mExtendedReturnSyncRoot)
{
ExtendedLookupRequestState currentState = GetExtendedLookupState(request.FieldName);
@@ -761,6 +785,8 @@ namespace Lskj.Control
}
ExtendedLookupQueryResult result = QueryExtendedReturn(request);
if (mExtendedReturnDisposed) return;
bool deliverResult = false;
ExtendedLookupRequest nextRequest = null;
lock (mExtendedReturnSyncRoot)
@@ -928,11 +954,11 @@ namespace Lskj.Control
private void BeginInvokeExtendedReturnResult(ExtendedLookupRequest request, ExtendedLookupQueryResult result)
{
if (this.IsDisposed || !this.IsHandleCreated) return;
if (mExtendedReturnDisposed || this.IsDisposed || !this.IsHandleCreated) return;
MethodInvoker deliver = new MethodInvoker(delegate
{
if (this.IsDisposed || request.Editor == null || request.Editor.IsDisposed) return;
if (mExtendedReturnDisposed || this.IsDisposed || request.Editor == null || request.Editor.IsDisposed) return;
if (!object.ReferenceEquals(this.GridView.ActiveEditor, request.Editor)) return;
if (this.GridView.FocusedColumn == null ||
!string.Equals(this.GridView.FocusedColumn.FieldName, request.FieldName, StringComparison.OrdinalIgnoreCase)) return;
@@ -1286,6 +1312,8 @@ namespace Lskj.Control
/// </summary>
private void ResetExtendedReturnState()
{
if (mExtendedReturnDisposed) return;
DisposeExtendedReturnRequestTimers();
lock (mExtendedReturnSyncRoot)
{
@@ -1309,6 +1337,7 @@ namespace Lskj.Control
state.Version++;
state.DeliveredVersion = 0;
state.PendingRequest = null;
state.IsRunning = false;
if (state.DebounceTimer != null)
{
state.DebounceTimer.Change(Timeout.Infinite, Timeout.Infinite);
@@ -1318,5 +1347,163 @@ namespace Lskj.Control
}
}
}
/// <summary>
/// 释放扩展返回专用的弹窗控件树和事件订阅。
/// PopupContainerControl 不在 GridControlEx.Controls 树中,不能依赖宿主控件的
/// 默认 Dispose 递归释放;这里必须显式切断事件和 GridView 的本地化器订阅。
/// </summary>
private void DisposeExtendedReturnResources()
{
lock (mExtendedReturnSyncRoot)
{
if (mExtendedReturnDisposed) return;
mExtendedReturnDisposed = true;
}
DisposeExtendedReturnRequestTimers();
try
{
if (mExtendedReturnDisplayEventAttached)
{
this.GridView.CustomColumnDisplayText -= GridView_CustomColumnDisplayText_ExtendedReturn;
mExtendedReturnDisplayEventAttached = false;
}
if (mExtendedReturnEditEventAttached)
{
this.GridView.CustomRowCellEditForEditing -= GridView_CustomRowCellEditForEditing_ExtendedReturn;
this.GridView.RowCellClick -= GridView_RowCellClick_ExtendedReturn;
mExtendedReturnEditEventAttached = false;
}
}
catch
{
// 宿主 GridView 可能已经进入 DevExpress 的销毁流程,释放必须继续。
}
try
{
this.Disposed -= GridControlEx_Disposed_ExtendedReturn;
mExtendedReturnDisposeEventAttached = false;
}
catch
{
}
List<ExtendedReturnPopupContext> contexts =
new List<ExtendedReturnPopupContext>(mExtendedReturnPopupContexts.Values);
List<RepositoryItemPopupContainerEdit> searchEditors =
new List<RepositoryItemPopupContainerEdit>(mExtendedReturnSearchEditors.Values);
mExtendedReturnPopupContexts.Clear();
mExtendedReturnSearchEditors.Clear();
foreach (ExtendedReturnPopupContext context in contexts)
{
DisposeExtendedReturnPopupContext(context);
}
// 防止异常配置导致某个 editor 没有对应 context 时仍然遗留事件订阅。
foreach (RepositoryItemPopupContainerEdit searchEdit in searchEditors)
{
DisposeExtendedReturnSearchEditor(searchEdit);
}
lock (mExtendedReturnSyncRoot)
{
foreach (DataTable schema in mExtendedReturnSchemas.Values)
{
DisposeExtendedReturnDataTable(schema);
}
mExtendedReturnSchemas.Clear();
mExtendedReturnSchemaSqls.Clear();
mExtendedReturnQueryStates.Clear();
mExtendedReturnSchemaGeneration++;
}
mExtendedReturnDisplayFields.Clear();
// 这些字段会在扩展返回弹窗操作中指向当前 GridView,销毁时不能继续保留引用。
CurrentOperGridView = null;
CurrentOperModel = null;
CurrentOperColumnKey = string.Empty;
}
private void DisposeExtendedReturnPopupContext(ExtendedReturnPopupContext context)
{
if (context == null) return;
PopupContainerEdit ownerEdit = context.OwnerEdit;
if (ownerEdit != null)
{
try
{
if (!ownerEdit.IsDisposed && ownerEdit.IsPopupOpen)
{
ownerEdit.ClosePopup();
}
}
catch
{
}
}
ExtendedReturnSearchPopup popup = context.Popup;
if (popup != null)
{
try { popup.SearchRequested -= ExtendedReturnSearch_SearchRequested; } catch { }
try { popup.ClearRequested -= ExtendedReturnSearch_ClearRequested; } catch { }
try { popup.ResultSelected -= ExtendedReturnSearch_ResultSelected; } catch { }
try { popup.ResultGrid.DataSource = null; } catch { }
try { popup.ClearResultAndFilter(); } catch { }
try { popup.Tag = null; } catch { }
}
PopupContainerControl popupControl = context.PopupControl;
if (popupControl != null)
{
try { popupControl.Tag = null; } catch { }
}
DisposeExtendedReturnSearchEditor(context.SearchEdit);
DisposeExtendedReturnComponent(popup == null ? null : popup.ResultView);
DisposeExtendedReturnComponent(popup == null ? null : popup.ResultGrid);
DisposeExtendedReturnComponent(popup);
DisposeExtendedReturnComponent(popupControl);
DisposeExtendedReturnComponent(context.DisplayEdit);
context.Model = null;
context.Popup = null;
context.PopupControl = null;
context.SearchEdit = null;
context.DisplayEdit = null;
context.OwnerEdit = null;
context.BusinessRow = null;
}
private void DisposeExtendedReturnSearchEditor(RepositoryItemPopupContainerEdit searchEdit)
{
if (searchEdit == null) return;
try { searchEdit.QueryPopUp -= ExtendedReturnSearch_QueryPopUp; } catch { }
try { searchEdit.Popup -= ExtendedReturnSearch_Popup; } catch { }
try { searchEdit.Closed -= ExtendedReturnSearch_Closed; } catch { }
try { searchEdit.QueryDisplayText -= ExtendedReturnSearch_QueryDisplayText; } catch { }
try { searchEdit.PopupControl = null; } catch { }
try { searchEdit.Tag = null; } catch { }
DisposeExtendedReturnComponent(searchEdit);
}
private static void DisposeExtendedReturnDataTable(DataTable table)
{
if (table == null) return;
try { table.Dispose(); } catch { }
}
private static void DisposeExtendedReturnComponent(IDisposable component)
{
if (component == null) return;
try { component.Dispose(); } catch { }
}
}
}
+119 -23
View File
@@ -564,6 +564,71 @@ namespace Lskj.Control
this.gridView.MouseWheel += GridView_MouseWheel;
}
private DbCommandBuilder _adapterCommandBuilder;
protected static void DisposeDataAdapter(DbDataAdapter adapter)
{
if (adapter == null)
{
return;
}
DbCommand[] commands =
{
adapter.SelectCommand,
adapter.InsertCommand,
adapter.UpdateCommand,
adapter.DeleteCommand
};
foreach (DbCommand command in commands)
{
try
{
command?.Dispose();
}
catch
{
// Resource cleanup must not break control disposal or a new query.
}
}
try
{
adapter.Dispose();
}
catch
{
// Resource cleanup must not break control disposal or a new query.
}
}
protected void SetAdapterCommandBuilder(DbDataAdapter adapter)
{
DisposeAdapterCommandBuilder();
if (adapter == null)
{
return;
}
_adapterCommandBuilder = SqlHelper.dbFactory.CreateCommandBuilder();
_adapterCommandBuilder.DataAdapter = adapter;
}
protected void DisposeAdapterCommandBuilder()
{
DbCommandBuilder commandBuilder = _adapterCommandBuilder;
_adapterCommandBuilder = null;
try
{
commandBuilder?.Dispose();
}
catch
{
// Resource cleanup must not break control disposal or a new query.
}
}
private void DisposeGridResources()
{
if (_gridResourcesDisposed)
@@ -578,9 +643,23 @@ namespace Lskj.Control
mTimer.Dispose();
mTimer = null;
}
try
{
if (GridControl != null)
{
GridControl.DataSource = null;
}
}
catch
{
// The inner DevExpress control may already be disposed.
}
DisposeColumnImageCaches(ColumnList);
DisposeRightMenuButtonImages();
ClearBarcodeImageCache();
DisposeAdapterCommandBuilder();
DisposeDataAdapter(AdapterObj);
AdapterObj = null;
mControlSourceDic.Clear();
mControlList.Clear();
ColumnList.Clear();
@@ -589,6 +668,9 @@ namespace Lskj.Control
ImageList.Clear();
RepeatedVerificationNames.Clear();
PromptMessage.Clear();
ParentControl = null;
Model = null;
SysModel = null;
if (_mainGridToolTipController != null)
{
_mainGridToolTipController.BeforeShow -= MainGvTool_BeforeShow;
@@ -599,6 +681,11 @@ namespace Lskj.Control
_mainGridToolTipController.Dispose();
_mainGridToolTipController = null;
}
if (customFont != null)
{
customFont.Dispose();
customFont = null;
}
}
private void PrepareForColumnRebuild()
@@ -2036,7 +2123,7 @@ namespace Lskj.Control
//}));
Task<DataTable> customColumnByDatabaseTask = cachesDic.AddTask(this, "CustomColumnByDatabase", new Task<DataTable>(() =>
{
return this.GridView.GetCustomColumnByDatabase(customColumKey);
return GridExtend.GetCustomColumnByDatabase(customColumKey);
}));
}
@@ -2171,12 +2258,14 @@ namespace Lskj.Control
{
if (adapter == null) return 0;
DbDataAdapter previousAdapter = this.AdapterObj;
bool adapterAssigned = false;
DataSet dataSet = null;
try
{
this.AdapterObj = adapter;
DataSet dataSet = new DataSet();
dataSet = new DataSet();
// 重连配置
int maxRetryCount = 2; // 次数
@@ -2215,7 +2304,23 @@ namespace Lskj.Control
}
}
DataTable dt = dataSet.Tables.Count > 0 ? dataSet.Tables[0] : null;
int rowCount = dt == null ? 0 : dt.Rows.Count;
if (dt != null)
{
// Detach the result table before releasing the temporary DataSet.
dataSet.Tables.Remove(dt);
}
dataSet.Dispose();
dataSet = null;
DisposeAdapterCommandBuilder();
if (previousAdapter != null && !ReferenceEquals(previousAdapter, adapter))
{
DisposeDataAdapter(previousAdapter);
}
this.AdapterObj = adapter;
adapterAssigned = true;
if (this.ColumnList == null || this.ColumnList.Count == 0)
{
@@ -2230,12 +2335,10 @@ namespace Lskj.Control
this.gridView.Columns.Clear();
}
}
DbCommandBuilder cb = SqlHelper.dbFactory.CreateCommandBuilder();
cb.DataAdapter = this.AdapterObj;
SetAdapterCommandBuilder(this.AdapterObj);
//this.GridControl.DataSource = dataSet.Tables[0];
//解决大小写问题后在赋值
DataTable dt = dataSet.Tables[0];
if (dt != null && this.gridView.Columns.Count > 0)
{
foreach (DataColumn column in dt.Columns)
@@ -2276,12 +2379,20 @@ namespace Lskj.Control
this.SetAutoColumns();
if (selectRowHandler)
this.gridView.SelectRowHandler(this.gridView.FocusedRowHandle);
return dataSet.Tables[0] != null ? dataSet.Tables[0].Rows.Count : 0;
return rowCount;
}
catch (Exception ex)
{
if (!adapterAssigned)
{
DisposeDataAdapter(adapter);
}
MessageUtil.Show(ex);
}
finally
{
dataSet?.Dispose();
}
return 0;
}
@@ -5536,9 +5647,7 @@ namespace Lskj.Control
/// <param name="e">事件参数。</param>
private void OnGridControlExDisposed(object sender, EventArgs e)
{
if (_gridResourcesDisposed) return;
_gridResourcesDisposed = true;
DisposeGridResources();
foreach (FrmModelLookUp2 modelLookUp in selectReturnModelLookUpCache.Values.Distinct())
{
if (modelLookUp != null && !modelLookUp.IsDisposed)
@@ -5548,19 +5657,6 @@ namespace Lskj.Control
}
selectReturnModelLookUpCache.Clear();
selectReturnDisplaySourceCache.Clear();
if (_mainGridToolTipController != null)
{
_mainGridToolTipController.BeforeShow -= MainGvTool_BeforeShow;
_mainGridToolTipController.Dispose();
_mainGridToolTipController = null;
}
if (customFont != null)
{
customFont.Dispose();
customFont = null;
}
}
/// <summary>
@@ -456,6 +456,7 @@
<Compile Include="BlinkBrowser.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="CefBrowserLifetimeCoordinator.cs" />
<Compile Include="BrowserSetting2\BsClient.cs" />
<Compile Include="BrowserSetting2\BsContextMenuHandler.cs" />
<Compile Include="BrowserSetting2\BsDownloadHandler.cs" />
@@ -29,6 +29,65 @@ namespace Lskj.Control.Model
public class BandedGridDragGrid : IDisposable
{
private bool _disposed;
internal static void DisposeRegistrations(
Dictionary<BandedGridView, List<BandedGridDragGrid>> sourceRegistrations,
Dictionary<GridView, List<BandedGridDragGrid>> targetRegistrations,
BandedGridView sourceGridView,
GridView targetGridView)
{
DisposeSourceRegistrations(sourceRegistrations, sourceGridView);
DisposeTargetRegistrations(targetRegistrations, targetGridView);
}
private static void DisposeSourceRegistrations(
Dictionary<BandedGridView, List<BandedGridDragGrid>> registrations,
BandedGridView gridView)
{
foreach (KeyValuePair<BandedGridView, List<BandedGridDragGrid>> entry in registrations.ToList())
{
bool removeKey = ReferenceEquals(entry.Key, gridView);
foreach (BandedGridDragGrid registration in entry.Value.ToList())
{
if (removeKey || registration == null || registration._disposed || registration.References(gridView))
{
if (registration != null)
registration.Dispose();
entry.Value.Remove(registration);
}
}
if (removeKey || entry.Value.Count == 0)
registrations.Remove(entry.Key);
}
}
private static void DisposeTargetRegistrations(
Dictionary<GridView, List<BandedGridDragGrid>> registrations,
GridView gridView)
{
foreach (KeyValuePair<GridView, List<BandedGridDragGrid>> entry in registrations.ToList())
{
bool removeKey = ReferenceEquals(entry.Key, gridView);
foreach (BandedGridDragGrid registration in entry.Value.ToList())
{
if (removeKey || registration == null || registration._disposed || registration.References(gridView))
{
if (registration != null)
registration.Dispose();
entry.Value.Remove(registration);
}
}
if (removeKey || entry.Value.Count == 0)
registrations.Remove(entry.Key);
}
}
internal bool References(GridView gridView)
{
return gridView != null &&
(ReferenceEquals(_sourceGridView, gridView) ||
ReferenceEquals(_targetGridView, gridView));
}
/// <summary>
/// 是否正在拖拽
/// </summary>
@@ -32,6 +32,43 @@ namespace Lskj.Control.Model
public class GridDragGrid : IDisposable
{
private bool _disposed;
internal static void DisposeRegistrations(
Dictionary<GridView, List<GridDragGrid>> sourceRegistrations,
Dictionary<GridView, List<GridDragGrid>> targetRegistrations,
GridView gridView)
{
DisposeRegistrations(sourceRegistrations, gridView);
DisposeRegistrations(targetRegistrations, gridView);
}
private static void DisposeRegistrations(
Dictionary<GridView, List<GridDragGrid>> registrations,
GridView gridView)
{
foreach (KeyValuePair<GridView, List<GridDragGrid>> entry in registrations.ToList())
{
bool removeKey = ReferenceEquals(entry.Key, gridView);
foreach (GridDragGrid registration in entry.Value.ToList())
{
if (removeKey || registration == null || registration._disposed || registration.References(gridView))
{
if (registration != null)
registration.Dispose();
entry.Value.Remove(registration);
}
}
if (removeKey || entry.Value.Count == 0)
registrations.Remove(entry.Key);
}
}
internal bool References(GridView gridView)
{
return gridView != null &&
(ReferenceEquals(_sourceGridView, gridView) ||
ReferenceEquals(_targetGridView, gridView));
}
/// <summary>
/// 是否正在拖拽
/// </summary>
@@ -101,7 +101,6 @@ namespace Lskj.Control.Model
_gridView = null;
_treeView = null;
}
/// <summary>
/// <para>说明:获取表格选中行数据</para>
+9 -12
View File
@@ -913,6 +913,14 @@ namespace Lskj.Control.Model
/// <param name="key">The key.</param>
/// <returns>DataTable.</returns>
public static DataTable GetCustomColumnByDatabase(this GridView gridView, string key)
{
return GetCustomColumnByDatabase(key);
}
/// <summary>
/// 获取个性配置列数据,不依赖任何界面控件。
/// </summary>
public static DataTable GetCustomColumnByDatabase(string key)
{
try
{
@@ -954,18 +962,7 @@ namespace Lskj.Control.Model
{
BaseImpl.ExecSqlValue("alter table " + ResourceKeys.SettingTableName + " add IfFixColumn bit");
}
// 读取普通用户读取个人配置,没有则读取管理员配置,管理未配置则读取系统默认.逐级上报读取方式.
string sqlValue = string.Format("select * from {0} where formKey='{1}' and operatorid='{2}' order by orderid ", ResourceKeys.SettingTableName, key, ERPInfo.Instance.UserId);
DataTable table = BaseImpl.GetDataTableResult(sqlValue);
//if (table == null || table.Rows.Count == 0)
//{
// sqlValue = string.Format("select * from {0} where formKey='{1}' and operatorid='{2}'", ResourceKeys.SettingTableName, key, ERPInfo.Instance.UserManager);
// table = BaseImpl.GetDataTableResult(sqlValue);
//}
return table;
return GetCustomColumnByDatabase(key);
}
catch (Exception)
{
+273 -59
View File
@@ -32,8 +32,10 @@ namespace Lskj.Control.Model
/// <summary>
/// 查询控件、添加修改界面控件管理类
/// </summary>
public class MyControl
public class MyControl : IDisposable
{
private const long UserSearchCooldownTicks =
TimeSpan.TicksPerMillisecond * 350;
private string _searchSql;
private DataTable _controls;
private DataTable _schemes;
@@ -46,8 +48,12 @@ namespace Lskj.Control.Model
private GridControlEx _gridLeft;
private TreeViewEx _tvLeft;
private MyControl _leftSearch;
private DropDownButton _dropDown = new DropDownButton();
private PopupMenu _popupMenu = new PopupMenu();
private DropDownButton _dropDown;
private PopupMenu _popupMenu;
private bool mDisposed;
private bool mUserSearchInProgress;
private long mLastUserSearchCompletedTicks;
private int mAcceptedUserSearchCount;
/// <summary>
/// 计算字段
/// </summary>
@@ -112,6 +118,10 @@ namespace Lskj.Control.Model
/// </summary>
/// <value>The button object.</value>
public SimpleButton ButtonObj { get { return _button; } }
public int AcceptedUserSearchCount
{
get { return mAcceptedUserSearchCount; }
}
/// <summary>
/// 条件数据源刷新按钮
/// </summary>
@@ -1031,6 +1041,10 @@ namespace Lskj.Control.Model
// 创建模版搜索
if (_schemes != null && ModuleId > 0 && _schemes.Rows.Count > 0)
{
if (_popupMenu == null)
{
_popupMenu = new PopupMenu();
}
_dropDown = new DropDownButton();
_dropDown.DropDownArrowStyle = DropDownArrowStyle.Show;
_dropDown.DropDownControl = this._popupMenu;
@@ -1222,6 +1236,10 @@ namespace Lskj.Control.Model
// 创建模版搜索
if (_schemes != null && ModuleId > 0 && _schemes.Rows.Count > 0)
{
if (_popupMenu == null)
{
_popupMenu = new PopupMenu();
}
_dropDown = new DropDownButton();
_dropDown.DropDownArrowStyle = DropDownArrowStyle.Show;
_dropDown.DropDownControl = this._popupMenu;
@@ -1758,8 +1776,14 @@ namespace Lskj.Control.Model
WaitForm.HideForm();
mControlSourceDic.Clear();
if (this.OnDataSourceBindCallBack != null) this.OnDataSourceBindCallBack(this, null);
this.mTimer.Stop();
this.mTimer.Dispose();
Timer timer = this.mTimer;
this.mTimer = null;
if (timer != null)
{
timer.Tick -= mTimerTick;
timer.Stop();
timer.Dispose();
}
}
}
}
@@ -6113,6 +6137,61 @@ namespace Lskj.Control.Model
}
}
private bool TryBeginUserSearch()
{
if (mDisposed || mUserSearchInProgress)
{
return false;
}
long now = DateTime.UtcNow.Ticks;
if (mLastUserSearchCompletedTicks > 0 &&
now - mLastUserSearchCompletedTicks < UserSearchCooldownTicks)
{
return false;
}
mUserSearchInProgress = true;
mAcceptedUserSearchCount++;
return true;
}
private void EndUserSearch()
{
mUserSearchInProgress = false;
mLastUserSearchCompletedTicks = DateTime.UtcNow.Ticks;
}
private bool ExecuteUserSearch(object sender, EventArgs e)
{
if (!TryBeginUserSearch())
{
return false;
}
try
{
SearchArgs args = new SearchArgs();
if (OnSearchBeforeCallBack != null)
{
OnSearchBeforeCallBack(sender, args);
}
if (args.Continue)
{
this.SearchGrid(false);
}
if (OnSearchAfterCallBack != null)
{
OnSearchAfterCallBack(sender, e);
}
return true;
}
finally
{
EndUserSearch();
}
}
/// <summary>
/// <para>说明:</para>
/// <para>创建人:龚宇超</para>
@@ -6137,18 +6216,8 @@ namespace Lskj.Control.Model
{
if (baseControl.Model.IsSearchControl)
{
// 搜索控件回车直接搜索
SearchArgs args = new SearchArgs();
// 查询之前
if (OnSearchBeforeCallBack != null)
OnSearchBeforeCallBack(sender, args);
if (args.Continue) this.SearchGrid(false);
// 查询之后
if (OnSearchAfterCallBack != null) OnSearchAfterCallBack(sender, e);
if (baseControl.Model.ScanAfterEmpty)
if (ExecuteUserSearch(sender, e) &&
baseControl.Model.ScanAfterEmpty)
{
baseControl.EditText = string.Empty;
}
@@ -6247,14 +6316,7 @@ namespace Lskj.Control.Model
{
if (baseControl.Model.IsSearchControl)
{
// 搜索控件回车直接搜索
SearchArgs args = new SearchArgs();
// 查询之前
if (OnSearchBeforeCallBack != null)
OnSearchBeforeCallBack(sender, args);
if (args.Continue) this.SearchGrid(false);
// 查询之后
if (OnSearchAfterCallBack != null) OnSearchAfterCallBack(sender, e);
ExecuteUserSearch(sender, e);
}
}
}
@@ -6271,45 +6333,57 @@ namespace Lskj.Control.Model
/// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
protected void OnSimpleButtonClick(object sender, EventArgs e)
{
if (!TryBeginUserSearch())
{
return;
}
try
{
if (Model != null)
try
{
bool allowBefore = ApiHelper.IsExecEventApi(Interface.Api.OperateEvent.BeforeSearchBtnClick, Model.ModuleCode, 0);
//查询前调用Api接口
if (allowBefore)
if (Model != null)
{
DataRow dataRow = this.GetAllControlValueRow();
ApiHelper apiHelper = new ApiHelper(Model.ModuleCode, 0, dataRow);
apiHelper.OnEvent(Interface.Api.OperateEvent.BeforeSearchBtnClick, Interface.Api.ActionType.None);
if (apiHelper.apiHandlerModels.Count > 0)
bool allowBefore = ApiHelper.IsExecEventApi(Interface.Api.OperateEvent.BeforeSearchBtnClick, Model.ModuleCode, 0);
//查询前调用Api接口
if (allowBefore)
{
Hashtable hashtable = apiHelper.apiHandlerModels[apiHelper.apiHandlerModels.Count - 1].resultPmsHashtables[0];
if (hashtable.ContainsKey("result"))
DataRow dataRow = this.GetAllControlValueRow();
ApiHelper apiHelper = new ApiHelper(Model.ModuleCode, 0, dataRow);
apiHelper.OnEvent(Interface.Api.OperateEvent.BeforeSearchBtnClick, Interface.Api.ActionType.None);
if (apiHelper.apiHandlerModels.Count > 0)
{
string jsonResult = hashtable["result"] + "";
DataTable dataTable = JsonConvert.DeserializeObject<DataTable>(jsonResult);
this._mainGridEx.SetGridViewDataSource(dataTable);
return;
Hashtable hashtable = apiHelper.apiHandlerModels[apiHelper.apiHandlerModels.Count - 1].resultPmsHashtables[0];
if (hashtable.ContainsKey("result"))
{
string jsonResult = hashtable["result"] + "";
DataTable dataTable = JsonConvert.DeserializeObject<DataTable>(jsonResult);
this._mainGridEx.SetGridViewDataSource(dataTable);
return;
}
}
}
}
}
catch (Exception ex)
{
MessageUtil.Show(ex.Message);
}
SearchArgs args = new SearchArgs();
// 查询之前
if (OnSearchBeforeCallBack != null)
OnSearchBeforeCallBack(sender, args);
if (args.Continue) this.SearchGrid(false);
// 查询之后
if (OnSearchAfterCallBack != null) OnSearchAfterCallBack(sender, e);
}
catch (Exception ex)
finally
{
MessageUtil.Show(ex.Message);
EndUserSearch();
}
SearchArgs args = new SearchArgs();
// 查询之前
if (OnSearchBeforeCallBack != null)
OnSearchBeforeCallBack(sender, args);
if (args.Continue) this.SearchGrid(false);
// 查询之后
if (OnSearchAfterCallBack != null) OnSearchAfterCallBack(sender, e);
}
@@ -6344,15 +6418,7 @@ namespace Lskj.Control.Model
/// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
protected void OnFixButtonClick(object sender, EventArgs e)
{
SearchArgs args = new SearchArgs();
// 查询之前
if (OnSearchBeforeCallBack != null)
OnSearchBeforeCallBack(sender, args);
if (args.Continue) this.SearchGrid(false);
// 查询之后
if (OnSearchAfterCallBack != null) OnSearchAfterCallBack(sender, e);
ExecuteUserSearch(sender, e);
}
/// <summary>
/// <para>说明:高级搜索按钮鼠标离开时</para>
@@ -6738,6 +6804,154 @@ namespace Lskj.Control.Model
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!disposing || mDisposed)
{
return;
}
mDisposed = true;
mUserSearchInProgress = false;
Timer timer = mTimer;
mTimer = null;
if (timer != null)
{
try
{
timer.Tick -= mTimerTick;
timer.Stop();
timer.Dispose();
}
catch
{
// A completed delayed-load timer may already be disposed.
}
}
if (_button != null)
{
_button.Click -= OnSimpleButtonClick;
_button.Tag = null;
}
if (_fixButton != null)
{
_fixButton.Click -= OnFixButtonClick;
}
if (_refreshButton != null)
{
_refreshButton.Click -= OnRefreshButtonClick;
_refreshButton.Tag = null;
}
if (btnCondSearch != null)
{
btnCondSearch.Click -= OnBtnCondSearchClick;
btnCondSearch.Tag = null;
}
if (_dropDown != null)
{
_dropDown.Leave -= OnDropDownLeave;
_dropDown.DropDownControl = null;
}
foreach (SimpleButton button in mrpBtnDic.Values.Distinct())
{
if (button != null)
{
button.Click -= OnModuleClick;
button.Tag = null;
}
}
BarManager searchSchemeManager =
_popupMenu == null ? null : _popupMenu.Manager;
if (_popupMenu != null)
{
_popupMenu.Manager = null;
_popupMenu.ItemLinks.Clear();
_popupMenu.Dispose();
}
if (searchSchemeManager != null)
{
searchSchemeManager.Dispose();
}
if (_mainGridEx != null &&
ReferenceEquals(_mainGridEx.ParentControl, this))
{
_mainGridEx.ParentControl = null;
}
try
{
if (Model != null && Model.DataCaches != null)
{
Model.DataCaches.Remove(this);
}
}
catch
{
// Cache cleanup must not interrupt module disposal.
}
preSearchVerification = null;
OnSearchBeforeCallBack = null;
OnSearchAfterCallBack = null;
OnAddCallBack = null;
ClearDetails = null;
OnLastQueryTriggered = null;
OnSourceRefrshCallBack = null;
OnDataSourceBindCallBack = null;
OnDataFileRefrshCallBack = null;
OpenDocumentSource = null;
_calcControls.Clear();
_models.Clear();
mControlList.Clear();
mExtendedReturnSearchControls.Clear();
mExtendedReturnPendingChanges.Clear();
mControlSourceDic.Clear();
mCacheDictionary.Clear();
DetailSelection.Clear();
changeLabelAutoGridLooks.Clear();
mrpBtnDic.Clear();
ModuleResultDic.Clear();
ParaContrlsDic.Clear();
_controls = null;
_schemes = null;
_fixField = null;
_fixKey = null;
_button = null;
_fixButton = null;
_refreshButton = null;
_dropDown = null;
_popupMenu = null;
btnCondSearch = null;
_gridControl = null;
_mainGridEx = null;
_gridLeft = null;
_tvLeft = null;
_leftSearch = null;
_parentPanel = null;
CurrentData = null;
SystemModel = null;
SaveCondTab = null;
mrpDyncModel = null;
Model = null;
popUpDyncModel = null;
rightItemLinks = null;
SpecialLeftTable = null;
beforeData = null;
OtherParams = null;
}
}
}
@@ -7,11 +7,94 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using WinFormsControl = System.Windows.Forms.Control;
namespace Lskj.Control.Model
{
public static class StaticBandedControl
{
public static void ReleaseModuleReferences(WinFormsControl moduleRoot, XtraTabPage modulePage, string moduleCode)
{
try
{
List<BandedGridView> bandedViews = CollectBandedGridViews(moduleRoot);
List<GridView> targetViews = CollectTargetGridViews(moduleRoot);
foreach (BandedGridView view in bandedViews)
BandedGridDragGrid.DisposeRegistrations(
BandedGridViewDragGridDic,
BandedTargetViewDragGridDic,
view,
null);
foreach (GridView view in targetViews)
BandedGridDragGrid.DisposeRegistrations(
BandedGridViewDragGridDic,
BandedTargetViewDragGridDic,
null,
view);
if (SourceDragBandedGridView != null &&
(bandedViews.Contains(SourceDragBandedGridView) ||
(SourceDragBandedGridView.GridControl != null && SourceDragBandedGridView.GridControl.IsDisposed)))
SourceDragBandedGridView = null;
RemoveConditionPanels(moduleCode);
while (modulePage != null && DogVerifyModuleForms.Remove(modulePage))
{
}
}
catch (Exception exception)
{
System.Diagnostics.Debug.WriteLine("释放旧 Banded 模块引用失败:" + exception);
}
}
private static List<BandedGridView> CollectBandedGridViews(WinFormsControl root)
{
List<BandedGridView> result = new List<BandedGridView>();
if (root == null)
return result;
foreach (WinFormsControl control in EnumerateControls(root))
{
DevExpress.XtraGrid.GridControl grid = control as DevExpress.XtraGrid.GridControl;
BandedGridView view = grid == null ? null : grid.MainView as BandedGridView;
if (view != null && !result.Contains(view))
result.Add(view);
}
return result;
}
private static List<GridView> CollectTargetGridViews(WinFormsControl root)
{
List<GridView> result = new List<GridView>();
if (root == null)
return result;
foreach (WinFormsControl control in EnumerateControls(root))
{
DevExpress.XtraGrid.GridControl grid = control as DevExpress.XtraGrid.GridControl;
GridView view = grid == null ? null : grid.MainView as GridView;
if (view != null && !result.Contains(view))
result.Add(view);
}
return result;
}
private static IEnumerable<WinFormsControl> EnumerateControls(WinFormsControl root)
{
yield return root;
foreach (WinFormsControl child in root.Controls)
foreach (WinFormsControl nested in EnumerateControls(child))
yield return nested;
}
private static void RemoveConditionPanels(string moduleCode)
{
foreach (string key in ConditionsPanelDic.Keys.ToList())
{
ModuleConditionsPanelEx panel;
if (string.Equals(key, moduleCode, StringComparison.OrdinalIgnoreCase) ||
!ConditionsPanelDic.TryGetValue(key, out panel) || panel == null || panel.IsDisposed)
ConditionsPanelDic.Remove(key);
}
}
/// <summary>
/// 记录当前U盾权限窗口
/// </summary>
@@ -44,4 +127,4 @@ namespace Lskj.Control.Model
/// </summary>
public static FrmProgressBar frmProgressBar;
}
}
}
+199 -1
View File
@@ -3,17 +3,215 @@ using DevExpress.XtraTab;
using Lskj.Control.ZKFinger;
using Lskj.Util;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Lskj.Model;
using System.Reflection;
using WinFormsControl = System.Windows.Forms.Control;
namespace Lskj.Control.Model
{
public static class StaticControl
{
/// <summary>
/// Releases static references owned by a closed legacy module. Cleanup is
/// best-effort so it cannot change the module close result.
/// </summary>
public static void ReleaseModuleReferences(WinFormsControl moduleRoot, XtraTabPage modulePage, string moduleCode)
{
List<GridView> gridViews = new List<GridView>();
try
{
gridViews = CollectGridViews(moduleRoot);
}
catch (Exception exception)
{
TraceCleanupFailure("收集表格引用", exception);
}
try
{
foreach (GridView gridView in gridViews)
{
try
{
RemoveGridReferences(gridView);
}
catch (Exception exception)
{
TraceCleanupFailure("释放表格拖拽引用", exception);
}
}
TryCleanup(() => RemoveConditionPanels(moduleCode), "释放条件面板引用");
TryCleanup(() => RemoveProtectedReferences(moduleRoot, modulePage), "释放权限保护引用");
TryCleanup(() => ClearRightMenuReferences(moduleRoot, gridViews), "释放右键菜单引用");
TryCleanup(
() => StaticBandedControl.ReleaseModuleReferences(moduleRoot, modulePage, moduleCode),
"释放带状表格引用");
}
finally
{
// DynamicModel caches retain completed tasks, result tables and
// their closures. Always release them after other references.
TryCleanup(() => ClearDataCaches(moduleRoot), "释放动态数据缓存");
}
}
private static void TryCleanup(Action cleanup, string operation)
{
try
{
cleanup();
}
catch (Exception exception)
{
TraceCleanupFailure(operation, exception);
}
}
private static void TraceCleanupFailure(string operation, Exception exception)
{
Debug.WriteLine("释放旧模块引用失败[" + operation + "]" + exception);
}
private static List<GridView> CollectGridViews(WinFormsControl root)
{
List<GridView> result = new List<GridView>();
if (root == null)
return result;
foreach (WinFormsControl control in EnumerateControls(root))
{
DevExpress.XtraGrid.GridControl grid = control as DevExpress.XtraGrid.GridControl;
GridView view = grid == null ? null : grid.MainView as GridView;
if (view != null && !result.Contains(view))
result.Add(view);
}
return result;
}
private static IEnumerable<WinFormsControl> EnumerateControls(WinFormsControl root)
{
yield return root;
foreach (WinFormsControl child in root.Controls)
foreach (WinFormsControl nested in EnumerateControls(child))
yield return nested;
}
private static void RemoveGridReferences(GridView gridView)
{
GridDragGrid.DisposeRegistrations(GridViewDragGridDic, TargetViewDragGridDic, gridView);
if (ReferenceEquals(SourceDragGridView, gridView) ||
(SourceDragGridView != null && SourceDragGridView.GridControl != null && SourceDragGridView.GridControl.IsDisposed))
SourceDragGridView = null;
}
private static void RemoveConditionPanels(string moduleCode)
{
foreach (string key in ConditionsPanelDic.Keys.ToList())
{
ModuleConditionsPanelEx panel;
if (string.Equals(key, moduleCode, StringComparison.OrdinalIgnoreCase) ||
!ConditionsPanelDic.TryGetValue(key, out panel) || panel == null || panel.IsDisposed)
ConditionsPanelDic.Remove(key);
}
}
private static void RemoveProtectedReferences(WinFormsControl root, XtraTabPage page)
{
while (page != null && DogVerifyModuleForms.Remove(page))
{
}
foreach (XtraTabPage item in DogVerifyModuleForms.ToList())
if (item == null || item.IsDisposed || IsContained(root, item))
DogVerifyModuleForms.Remove(item);
foreach (IForm item in DogVerifyNoPageForms.ToList())
if (item == null || item.SubForm == null || item.SubForm.IsDisposed || IsContained(root, item.SubForm))
DogVerifyNoPageForms.Remove(item);
}
private static bool IsContained(WinFormsControl root, WinFormsControl value)
{
if (root == null || value == null)
return false;
if (ReferenceEquals(root, value))
return true;
foreach (WinFormsControl child in root.Controls)
if (IsContained(child, value))
return true;
return false;
}
private static void ClearRightMenuReferences(WinFormsControl root, List<GridView> gridViews)
{
if (_RightMenuGridView != null && (gridViews.Contains(_RightMenuGridView) ||
(_RightMenuGridView.GridControl != null && _RightMenuGridView.GridControl.IsDisposed)))
RightMenuGridView = null;
if (RightMenuMyControl != null && RightMenuMyControl.MainGridEx != null &&
(RightMenuMyControl.MainGridEx.IsDisposed || IsContained(root, RightMenuMyControl.MainGridEx)))
RightMenuMyControl = null;
if (BomUnionPage != null && (BomUnionPage.IsDisposed || IsContained(root, BomUnionPage)))
BomUnionPage = null;
if (AddParentGrid.Value != null && (AddParentGrid.Value.IsDisposed || IsContained(root, AddParentGrid.Value)))
AddParentGrid = new KeyValuePair<string, GridControlEx>();
}
private static void ClearDataCaches(WinFormsControl root)
{
if (root == null)
return;
// Clear the root first because child enumeration can fail while a
// DevExpress control is disposing its child collection.
ClearDynamicModels(root);
try
{
foreach (WinFormsControl control in EnumerateControls(root).Skip(1).ToList())
ClearDynamicModels(control);
}
catch (Exception exception)
{
TraceCleanupFailure("遍历动态数据缓存", exception);
}
}
private static void ClearDynamicModels(object instance)
{
if (instance == null)
return;
BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
for (Type type = instance.GetType(); type != null; type = type.BaseType)
foreach (FieldInfo field in type.GetFields(flags | BindingFlags.DeclaredOnly))
try
{
ClearDynamicModel(field.GetValue(instance));
}
catch (Exception exception)
{
Debug.WriteLine("清理动态缓存字段失败:" + exception);
}
}
private static void ClearDynamicModel(object value)
{
DynamicModel model = value as DynamicModel;
if (model == null || model.DataCaches == null)
return;
Dictionary<object, Hashtable> caches = model.DataCaches;
foreach (Hashtable cache in caches.Values.OfType<Hashtable>().ToList())
{
foreach (IDisposable item in cache.Values.OfType<IDisposable>().ToList())
try { item.Dispose(); } catch { }
cache.Clear();
}
caches.Clear();
model.DataCaches = null;
}
/// <summary>
/// 记录当前U盾权限窗口
/// </summary>
@@ -84,4 +282,4 @@ namespace Lskj.Control.Model
}
}
}
+6 -2
View File
@@ -13,9 +13,13 @@
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
if (disposing)
{
components.Dispose();
ReleaseResourcesForDispose();
if (components != null)
{
components.Dispose();
}
}
base.Dispose(disposing);
}
+154 -20
View File
@@ -63,6 +63,7 @@ namespace Lskj.Control
/// </summary>
private MyControl _leftGridSearchObj;
private GridDragTree _gridDragTree;
private bool mModuleResourcesReleased;
private GridDragGrid _gridDragGrid;
private BandedGridDragGrid _bandedGridDragGrid;
@@ -156,6 +157,150 @@ namespace Lskj.Control
this.Disposed += OnModuleExDisposed;
}
public void ReleaseResourcesForDispose()
{
if (mModuleResourcesReleased)
{
return;
}
mModuleResourcesReleased = true;
HashSet<ModuleGridDetailEx> details =
new HashSet<ModuleGridDetailEx>();
HashSet<ModuleGridEx> grids = new HashSet<ModuleGridEx>();
foreach (System.Windows.Forms.Control control in
EnumerateModuleControls(this))
{
ModuleGridDetailEx detail = control as ModuleGridDetailEx;
if (detail != null)
{
details.Add(detail);
}
ModuleGridEx grid = control as ModuleGridEx;
if (grid != null)
{
grids.Add(grid);
}
}
foreach (ModuleGridDetailEx detail in details)
{
detail.ReleaseResourcesForDispose();
}
foreach (ModuleGridEx grid in grids)
{
grid.SaveEvent -= SetDetailGridView;
grid.OnExportCallBack -= SetExportGridView;
grid.ReleaseResourcesForDispose();
}
MyControl leftSearch = _leftGridSearchObj;
_leftGridSearchObj = null;
if (leftSearch != null)
{
leftSearch.OnDataSourceBindCallBack -= OnLeftControlObjDataSourceBindCallBack;
leftSearch.Dispose();
}
GridDragTree dragTree = _gridDragTree;
_gridDragTree = null;
if (dragTree != null)
{
dragTree.OnDragComplete -= OnDragTreeCompleted;
dragTree.Dispose();
}
GridDragGrid dragGrid = _gridDragGrid;
_gridDragGrid = null;
if (dragGrid != null)
{
dragGrid.OnDragComplete -= OnDragGridCompleted;
dragGrid.Dispose();
}
BandedGridDragGrid bandedDragGrid = _bandedGridDragGrid;
_bandedGridDragGrid = null;
if (bandedDragGrid != null)
{
bandedDragGrid.OnDragComplete -= OnDragBandedGridCompleted;
bandedDragGrid.Dispose();
}
try
{
if (treeLeft != null)
{
treeLeft.TreeNodeSelectAfter -= OnTreeLeftTreeNodeSelected;
treeLeft.OnTreeNodeMouseDoubleClick -= TreeLeft_OnTreeNodeMouseDoubleClick;
}
if (gridLeft != null && gridLeft.GridView != null)
{
gridLeft.GridView.RowClick -= OnGridViewRowClick;
}
if (treeGridLeft != null && treeGridLeft.TreeListObj != null)
{
treeGridLeft.TreeListObj.Click -= TreeListObj_Click;
treeGridLeft.TreeListObj.BeforeExpand -= TreeListObj_BeforeExpand;
treeGridLeft.TreeListObj.BeforeCollapse -= TreeListObj_BeforeCollapse;
}
if (MainBodyTab != null)
{
MainBodyTab.SelectedPageChanged -= MainBodyTab_SelectedPageChanged;
}
if (excelControlEx1 != null)
{
excelControlEx1.SaveCallBack -= OnExcelSaveClick;
}
}
catch
{
// A partially disposed child control must not stop cleanup.
}
try
{
if (Model != null && Model.DataCaches != null)
{
Model.DataCaches.Remove(this);
}
}
catch
{
// Cache cleanup must not interrupt module disposal.
}
OnLeftGridViewRowClickCallBack = null;
OnLeftTreeViewRowClickCallBack = null;
if (Details != null)
{
Details.Clear();
}
LeftRowObj = null;
ColumnNameTable = null;
_currentRow = null;
ExcelControlObj = null;
Model = null;
SysModel = null;
}
private static IEnumerable<System.Windows.Forms.Control>
EnumerateModuleControls(System.Windows.Forms.Control parent)
{
if (parent == null)
{
yield break;
}
foreach (System.Windows.Forms.Control child in parent.Controls)
{
yield return child;
foreach (System.Windows.Forms.Control nested in
EnumerateModuleControls(child))
{
yield return nested;
}
}
}
/// <summary>
/// Excel 控件包含 SpreadsheetControl、BarManager 和命令注册项,
/// 普通表格模块不应在设计器初始化阶段创建这些重型资源。
@@ -253,7 +398,11 @@ namespace Lskj.Control
if (Model.HasOperPrivilege() && model.IsBaseModule)
{
// 有权限则允许拖拽
_gridDragTree?.Dispose();
if (_gridDragTree != null)
{
_gridDragTree.OnDragComplete -= OnDragTreeCompleted;
_gridDragTree.Dispose();
}
_gridDragTree = new GridDragTree(this.ModuleGridObj.GridControlObj.GridView, this.treeLeft.TreeView);
_gridDragTree.CanDragParentNode = true;
_gridDragTree.OnDragComplete += new GridDragTreeCompleteEventHandler(OnDragTreeCompleted);
@@ -484,7 +633,6 @@ namespace Lskj.Control
{
case 1:
case 4://左侧为树节点
this.ModuleGridObj.LeftTreeViewEx = this.treeLeft;
Task<DataRow> baseLeftTreeFieldTask = cachesDic.AddTask(this, "BaseLeftTreeField", new Task<DataRow>(() =>
{
return BaseModuleImpl.GetBaseLeftTreeField(dynamicModel.ModuleCode);//获取表格左侧树字段
@@ -538,12 +686,7 @@ namespace Lskj.Control
DataTable customQueryFieldsTab = customQueryFieldsTask.Result;
if (customQueryFieldsTab != null && customQueryFieldsTab.Rows.Count > 0)
{
Task<MyControl> leftGridSearchObjTask = cachesDic.AddTask(this, "LeftGridSearchObj", new Task<MyControl>(() =>
{
string searchSql = baseLeftTreeFieldTask.Result["fieldsql"] + "";
return new MyControl(searchSql, sysModel.IsTreeTable ? this.treeGridLeft as GridControlEx : this.gridLeft);
}));
ModuleGridDetailObj._leftGridSearchObj = leftGridSearchObjTask.Result;
// MyControl 必须由后续 UI 初始化阶段创建。
}
else
{
@@ -565,7 +708,7 @@ namespace Lskj.Control
Task<DataTable> customColumnByDatabaseTask = cachesDic.AddTask(gridLeft, "CustomColumnByDatabase", new Task<DataTable>(() =>
{
string customColumKey = GridCustomColumnStruct.BaseLeftGridView + dynamicModel.ModuleCode;
return gridLeft.GridView.GetCustomColumnByDatabase(customColumKey);
return GridExtend.GetCustomColumnByDatabase(customColumKey);
}));
}
else
@@ -573,12 +716,11 @@ namespace Lskj.Control
Task<DataTable> customColumnByDatabaseTask = cachesDic.AddTask(treeGridLeft, "CustomColumnByDatabase", new Task<DataTable>(() =>
{
string customColumKey = GridCustomColumnStruct.BaseLeftGridView + dynamicModel.ModuleCode;
return treeGridLeft.GridView.GetCustomColumnByDatabase(customColumKey);
return GridExtend.GetCustomColumnByDatabase(customColumKey);
}));
}
}
}
ModuleGridObj.LeftGridEx = sysModel.IsTreeTable ? this.treeGridLeft : this.gridLeft;
break;
}
if (dynamicModel is DynamicExcelModel)//isExcel
@@ -2012,15 +2154,7 @@ namespace Lskj.Control
private void OnModuleExDisposed(object sender, EventArgs e)
{
this.Disposed -= OnModuleExDisposed;
_gridDragTree?.Dispose();
_gridDragTree = null;
_gridDragGrid?.Dispose();
_gridDragGrid = null;
_bandedGridDragGrid?.Dispose();
_bandedGridDragGrid = null;
ReleaseResourcesForDispose();
}
+6 -2
View File
@@ -13,9 +13,13 @@
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
if (disposing)
{
components.Dispose();
ReleaseResourcesForDispose();
if (components != null)
{
components.Dispose();
}
}
base.Dispose(disposing);
}
+83 -13
View File
@@ -39,6 +39,8 @@ namespace Lskj.Control
/// </summary>
public partial class ModuleGridDetailEx : UserControl
{
private bool mModuleResourcesReleased;
private bool mDetailPageCachesPrepared;
/// <summary>
/// 系统模块实体对象
@@ -147,6 +149,68 @@ namespace Lskj.Control
{
InitializeComponent();
}
internal void ReleaseResourcesForDispose()
{
if (mModuleResourcesReleased)
{
return;
}
mModuleResourcesReleased = true;
MyControl searchObj = SearchObj;
if (searchObj != null)
{
searchObj.OnSearchAfterCallBack -= SearchObj_ClearDetails_DoubleMode;
searchObj.OnLastQueryTriggered -= SearchObj_ClearDetails_DoubleMode;
searchObj.OnSearchAfterCallBack -= SearchObj_ClearDetails;
searchObj.OnLastQueryTriggered -= SearchObj_ClearDetails;
}
if (ModuleGridObj != null)
{
ModuleGridObj.AfterRefreshingCallBack -= ModuleGridObj_AfterRefreshingCallBack;
try
{
GridControlEx grid = ModuleGridObj.GridControlObj;
if (grid != null && grid.GridView != null)
{
grid.GridView.DoubleClick -= GridView_DoubleClick;
grid.GridView.DoubleClick -= OnGridViewDoubleClick;
grid.GridView.Click -= OnGridViewDoubleClick;
grid.GridView.MouseDown -= GridView_MouseDown;
grid.GridView.FocusedRowObjectChanged -= OnGridViewFocusedRowObjectChanged;
}
}
catch
{
// A partially disposed DevExpress view must not stop cleanup.
}
ModuleGridObj.ReleaseResourcesForDispose();
}
try
{
if (Model != null && Model.DataCaches != null)
{
Model.DataCaches.Remove(this);
}
}
catch
{
// Cache cleanup must not interrupt control disposal.
}
OnGridViewRowClickCallBack = null;
if (GridDetailList != null)
{
GridDetailList.Clear();
}
datamodel.Clear();
_leftGridSearchObj = null;
Model = null;
SysModel = null;
}
/// <summary>
/// <para>说明:初始化控件</para>
/// <para>创建人:龚宇超</para>
@@ -189,6 +253,7 @@ namespace Lskj.Control
}
else
{
PrepareDetailPageCaches(dataCaches);
// 初始化底部多标签
this.InitializePages();
}
@@ -220,7 +285,6 @@ namespace Lskj.Control
//获取通用数据
Task<ModuleModel> sysModelTask = cachesDic.GetTask<ModuleModel>(this, "SysModel");
Task<DynamicModel> dynamicModelTask = cachesDic.GetTask<DynamicModel>(this, "DynamicModel");
Task<List<GridDetailModel>> detailsTask = cachesDic.GetTask<List<GridDetailModel>>(this, "Details");
ModuleGridObj._leftGridSearchObj = _leftGridSearchObj;
Task<bool> getDataCachesTask = cachesDic.AddTask(this, "DataCaches", new Task<bool>(() =>
{
@@ -237,23 +301,29 @@ namespace Lskj.Control
{
cachesDic.AddTask(tcButtom, "ParentPrimaryKey", parentPrimaryKeyTask);
}
if (!string.IsNullOrEmpty(sysModel.MainModuleCodeField) && this.ModuleGridObj.GridControlObj.GridView.Columns.ColumnByFieldName(sysModel.MainModuleCodeField) != null)
{
//InitializeDynamicPages();
}
else
{
//添加数据到mControl
cachesDic.AddTask(tcButtom, "DynamicModel", dynamicModelTask);
cachesDic.AddTask(tcButtom, "Details", detailsTask);
// 初始化底部多标签
this.tcButtom.GetDataCaches(cachesDic);
}
}
return true;
}));
}
private void PrepareDetailPageCaches(
Dictionary<object, Hashtable> cachesDic)
{
if (mDetailPageCachesPrepared || cachesDic == null)
{
return;
}
mDetailPageCachesPrepared = true;
Task<DynamicModel> dynamicModelTask =
cachesDic.GetTask<DynamicModel>(this, "DynamicModel");
Task<List<GridDetailModel>> detailsTask =
cachesDic.GetTask<List<GridDetailModel>>(this, "Details");
cachesDic.AddTask(tcButtom, "DynamicModel", dynamicModelTask);
cachesDic.AddTask(tcButtom, "Details", detailsTask);
this.tcButtom.GetDataCaches(cachesDic);
}
/// <summary>
/// <para>说明:初始化底部多标签数据</para>
+1
View File
@@ -15,6 +15,7 @@
{
if (disposing)
{
ReleaseResourcesForDispose();
Lskj.Control.Model.PrintUtil.OnAfterPrint -=
new System.EventHandler(OnReportPrintAfter);
if (components != null)
+115 -36
View File
@@ -428,6 +428,7 @@ namespace Lskj.Control
/// 自定义查询条件
/// </summary>
public MyControl SearchObj { get; private set; }
private bool mModuleResourcesReleased;
/// <summary>
/// 左查询条件
/// </summary>
@@ -520,6 +521,24 @@ namespace Lskj.Control
searchObj = new MyControl(ReplaceBmpField(this.SysModel.MenuSql), gcMain, LeftTreeViewEx, LeftGridEx, _leftGridSearchObj);//替换sql语句中的bmp字段
searchObj.SpecialLeftTable = this.SpecialLeftTable;
searchObj.Model = Model;
if (!fixedQuery && Model.DataCaches != null)
{
searchObj.OtherParams = Model.OtherParams();
DynamicModel searchModel = Model;
DataTable searchControls = _queryTable;
Model.DataCaches.AddTask(searchObj, "DynamicModel",
new Task<DynamicModel>(() => searchModel));
Model.DataCaches.AddTask(searchObj, "ControlsTable",
new Task<DataTable>(() => searchControls));
searchObj.GetSearchDataCaches(Model.DataCaches);
}
}
if (this.MrpClickMenus == null && Model.DataCaches != null)
{
Model.DataCaches.GetValue(
this,
"UnionBaseGridRightMenus",
out this.MrpClickMenus);
}
this.SearchObj = searchObj;
// 搜索区域复用当前模块配置,MyControl 内部会校验模块号,不一致时仍按原逻辑查询。
@@ -2464,8 +2483,6 @@ namespace Lskj.Control
form.SubForm.Dispose();
form = null;
GC.Collect();
GC.WaitForPendingFinalizers();
}
}
catch (Exception ex)
@@ -3489,7 +3506,7 @@ namespace Lskj.Control
{
this.SearchObj.SearchLastGrid();
}
}
//GridColumnCollection gridColumns = this.gcMain.GridView.Columns;
@@ -3695,23 +3712,111 @@ namespace Lskj.Control
private void OnModuleGridExDisposed(object sender, EventArgs e)
{
this.Disposed -= OnModuleGridExDisposed;
ReleaseResourcesForDispose();
}
internal void ReleaseResourcesForDispose()
{
if (mModuleResourcesReleased)
{
return;
}
mModuleResourcesReleased = true;
PrintUtil.OnAfterPrint -= OnReportPrintAfter;
if (SearchObj != null)
MyControl searchObj = SearchObj;
SearchObj = null;
if (searchObj != null)
{
SearchObj.OnSearchBeforeCallBack -= OnSearchBeforeCallBack;
SearchObj.OnSearchAfterCallBack -= OnSearchAfterCallBack;
SearchObj.OnDataSourceBindCallBack -= OnMainSearchDataSourceBindCallBack;
if (ReferenceEquals(StaticControl.RightMenuMyControl, SearchObj))
searchObj.OnSearchBeforeCallBack -= OnSearchBeforeCallBack;
searchObj.OnSearchAfterCallBack -= OnSearchAfterCallBack;
searchObj.OnDataSourceBindCallBack -= OnMainSearchDataSourceBindCallBack;
if (ReferenceEquals(StaticControl.RightMenuMyControl, searchObj))
{
StaticControl.RightMenuMyControl = null;
}
searchObj.Dispose();
}
if (gcMain != null && ReferenceEquals(StaticControl.RightMenuGridView, gcMain.GridView))
try
{
StaticControl.RightMenuGridView = null;
if (gcMain != null)
{
if (ReferenceEquals(StaticControl.RightMenuGridView, gcMain.GridView))
{
StaticControl.RightMenuGridView = null;
}
if (gcMain.GridView != null)
{
gcMain.GridView.FocusedRowObjectChanged -= OnGridViewFocusedRowObjectChanged;
gcMain.GridView.ShowingEditor -= OnGridViewShowingEditor;
gcMain.GridView.DoubleClick -= OnGridViewDoubleClick;
gcMain.GridView.MouseDown -= OnGridViewMouseDown;
gcMain.GridView.MouseDown -= OnGridMouseDown;
gcMain.GridView.MouseMove -= OnGridMouseMove;
gcMain.GridView.MouseUp -= OnGridMouseUp;
}
if (gcMain.CustomGroupBandEx != null)
{
gcMain.CustomGroupBandEx.GridView.FocusedRowObjectChanged -= OnGridViewFocusedRowObjectChanged;
gcMain.CustomGroupBandEx.GridView.ShowingEditor -= OnGridViewShowingEditor;
}
if (gcMain.ParentControl != null &&
ReferenceEquals(gcMain.ParentControl, searchObj))
{
gcMain.ParentControl = null;
}
gcMain.Model = null;
gcMain.SysModel = null;
}
}
catch
{
// A partially disposed DevExpress view must not stop module cleanup.
}
try
{
if (Model != null && Model.DataCaches != null)
{
Model.DataCaches.Remove(this);
}
}
catch
{
// Cache cleanup must not interrupt control disposal.
}
OnSaveGridCallBack = null;
AfterDeleteGridCallBack = null;
RightGridCallBack = null;
DetailRightGridCallBack = null;
OnCloseCallback = null;
AfterRefreshingCallBack = null;
SaveEvent = null;
OnExportCallBack = null;
verifyDetailsTab = null;
if (m_dragRowShadow != null)
{
m_dragRowShadow.Dispose();
m_dragRowShadow = null;
}
ButtonModeRightMenus.Clear();
RightButtons.Clear();
itemCommonList.Clear();
LineStatus.Clear();
_leftGridSearchObj = null;
LeftTreeViewEx = null;
LeftGridEx = null;
SpecialLeftTable = null;
ParentGridEx = null;
ParentControlEx = null;
ParentControlObj = null;
TabObj = null;
Model = null;
SysModel = null;
}
/// <summary>
@@ -3993,32 +4098,6 @@ namespace Lskj.Control
{
return BaseModuleImpl.GetSchemesList(dynamicModel.ModuleId);//获取高级查询条件模版
}));
Task<DataTable> mrpClickMenusTask = cachesDic.GetTask<DataTable>(this, "UnionBaseGridRightMenus");
//InitializeQueryCondition
Task<MyControl> searchObjTask = cachesDic.AddTask(this, "SearchObj", new Task<MyControl>(() =>
{
DataTable queryTable = customQueryFieldsTask.Result;
bool fixedQuery = queryTable == null || queryTable.Rows.Count == 0;
if (MrpClickMenus == null && mrpClickMenusTask != null)
{
MrpClickMenus = mrpClickMenusTask.Result;
}
MyControl myControl = new MyControl(sysModel.MenuSql, gcMain, LeftTreeViewEx, LeftGridEx, _leftGridSearchObj)
{
SpecialLeftTable = this.SpecialLeftTable,
Model = dynamicModel,
SystemModel = sysModel,
MrpClickMenus = this.MrpClickMenus
};
if (!fixedQuery)
{
myControl.OtherParams = dynamicModel.OtherParams();
cachesDic.AddTask(myControl, "DynamicModel", dynamicModelTask);
cachesDic.AddTask(myControl, "ControlsTable", customQueryFieldsTask);
myControl.GetSearchDataCaches(cachesDic);
}
return myControl;
}));
// 搜索区域与当前模块共享同一个模块配置任务,避免再次查询模块信息。
cachesDic.AddTask(pl_top_search, "SysModel", sysModelTask);
//Task<DataTable> searchBaseGridRightMenusTask = cachesDic.AddTask(pl_top_search, "BaseGridRightMenus", new Task<DataTable>(() =>
+7 -2
View File
@@ -14,9 +14,14 @@ namespace Lskj.Control
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
if (disposing)
{
components.Dispose();
Lskj.Control.Model.PrintUtil.OnAfterPrint -=
new EventHandler(OnReportPrintAfter);
if (components != null)
{
components.Dispose();
}
}
base.Dispose(disposing);
}
+6 -2
View File
@@ -13,9 +13,13 @@
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
if (disposing)
{
components.Dispose();
ReleaseResourcesForDispose();
if (components != null)
{
components.Dispose();
}
}
base.Dispose(disposing);
}
+54 -6
View File
@@ -37,6 +37,8 @@ namespace Lskj.Control
/// </summary>
public partial class ReplacementDetailEx : UserControl
{
private bool mResourcesReleased;
private bool mDetailPageCachesPrepared;
/// <summary>
/// 系统模块实体对象
/// </summary>
@@ -102,6 +104,39 @@ namespace Lskj.Control
{
InitializeComponent();
}
internal void ReleaseResourcesForDispose()
{
if (mResourcesReleased)
{
return;
}
mResourcesReleased = true;
if (ModuleGridObj != null)
{
ModuleGridObj.ReleaseResourcesForDispose();
}
try
{
if (Model != null && Model.DataCaches != null)
{
Model.DataCaches.Remove(this);
}
}
catch
{
// Cache cleanup must not interrupt control disposal.
}
if (GridDetailList != null)
{
GridDetailList.Clear();
}
_leftGridSearchObj = null;
Model = null;
SysModel = null;
}
/// <summary>
/// <para>说明:初始化控件</para>
/// <para>创建人:龚宇超</para>
@@ -128,6 +163,7 @@ namespace Lskj.Control
this.ModuleGridObj.InitializeControl(sysModel, dyncModel);
RefreshDetail = this.SysModel.RefreshDetail == "0";
Console.WriteLine(DateTime.Now);
PrepareDetailPageCaches(dyncModel.DataCaches);
// 初始化底部多标签
this.InitializePages();
Console.WriteLine(DateTime.Now);
@@ -162,15 +198,27 @@ namespace Lskj.Control
//获取通用数据
Task<ModuleModel> sysModelTask = cachesDic.GetTask<ModuleModel>(this, "SysModel");
Task<DynamicModel> dynamicModelTask = cachesDic.GetTask<DynamicModel>(this, "DynamicModel");
Task<List<GridDetailModel>> detailsTask = cachesDic.GetTask<List<GridDetailModel>>(this, "Details");
cachesDic.AddTask(ModuleGridObj, "DynamicModel", dynamicModelTask);
cachesDic.AddTask(ModuleGridObj, "SysModel", sysModelTask);
cachesDic.AddTask(ModuleGridObj, "Details", detailsTask);
cachesDic.AddTask(tcButtom, "DynamicModel", dynamicModelTask);
cachesDic.AddTask(tcButtom, "Details", detailsTask);
//初始化顶部表格
ModuleGridObj.GetDataCaches(cachesDic);
// 初始化底部多标签
}
private void PrepareDetailPageCaches(
Dictionary<object, Hashtable> cachesDic)
{
if (mDetailPageCachesPrepared || cachesDic == null)
{
return;
}
mDetailPageCachesPrepared = true;
Task<DynamicModel> dynamicModelTask =
cachesDic.GetTask<DynamicModel>(this, "DynamicModel");
Task<List<GridDetailModel>> detailsTask =
cachesDic.GetTask<List<GridDetailModel>>(this, "Details");
cachesDic.AddTask(tcButtom, "DynamicModel", dynamicModelTask);
cachesDic.AddTask(tcButtom, "Details", detailsTask);
tcButtom.GetDataCaches(cachesDic);
}
@@ -650,4 +698,4 @@ namespace Lskj.Control
}
}
}
}
@@ -2112,6 +2112,7 @@ namespace Lskj.Control
public override int SetGridViewDataSource(DbDataAdapter adapter, bool selectRowHandler = true)
{
if (adapter == null) return 0;
DbDataAdapter previousAdapter = this.AdapterObj;
if (this.ColumnList == null || this.ColumnList.Count == 0)
{
this.gcMain.Bands.Clear();
@@ -2122,53 +2123,74 @@ namespace Lskj.Control
lastNodeIndex = 0;
if (selectRowHandler) lastNodeIndex = this.TreeListObj.GetVisibleIndexByNode(this.TreeListObj.FocusedNode);
this.AdapterObj = adapter;
DataSet dataSet = new DataSet();
//adapter.Fill(dataSet, "SetGridViewDataSource");
// 重连配置
int maxRetryCount = 2; // 次数
int retryDelay = 1000; // 等待时间
for (int i = 0; i < maxRetryCount; i++)
try
{
try
for (int i = 0; i < maxRetryCount; i++)
{
adapter.Fill(dataSet, "SetGridViewDataSource");
break;//连接成功
}
catch (SqlException ex)
{
// 判断是否是连接相关错误
if (IsConnectionError(ex.Number) ||
ex.Message.Contains("物理连接不可用") ||
ex.Message.Contains("传输级错误"))
try
{
if (i < maxRetryCount - 1)
adapter.Fill(dataSet, "SetGridViewDataSource");
break;//连接成功
}
catch (SqlException ex)
{
// 判断是否是连接相关错误
if (IsConnectionError(ex.Number) ||
ex.Message.Contains("物理连接不可用") ||
ex.Message.Contains("传输级错误"))
{
SqlConnection.ClearAllPools();
System.Threading.Thread.Sleep(retryDelay);
continue; // 重试
if (i < maxRetryCount - 1)
{
SqlConnection.ClearAllPools();
System.Threading.Thread.Sleep(retryDelay);
continue; // 重试
}
else
{
// 最后一次重试失败,抛出错误
throw new Exception($"经过 {maxRetryCount} 次重试后仍无法连接到数据库: {ex.Message}", ex);
}
}
else
{
// 最后一次重试失败,抛出错误
throw new Exception($"经过 {maxRetryCount} 次重试后仍无法连接到数据库: {ex.Message}", ex);
// 其他SQL错误直接抛出
throw;
}
}
else
{
// 其他SQL错误直接抛出
throw;
}
}
}
catch
{
dataSet.Dispose();
DisposeDataAdapter(adapter);
throw;
}
DataTable resultTable = dataSet.Tables.Count > 0 ? dataSet.Tables[0] : null;
int rowCount = resultTable == null ? 0 : resultTable.Rows.Count;
if (resultTable != null)
{
dataSet.Tables.Remove(resultTable);
}
dataSet.Dispose();
DbCommandBuilder cb = SqlHelper.dbFactory.CreateCommandBuilder();
cb.DataAdapter = this.AdapterObj;
DisposeAdapterCommandBuilder();
if (previousAdapter != null && !ReferenceEquals(previousAdapter, adapter))
{
DisposeDataAdapter(previousAdapter);
}
this.AdapterObj = adapter;
SetAdapterCommandBuilder(this.AdapterObj);
//SqlCommandBuilder cb = new SqlCommandBuilder(this.AdapterObj);
GetTreeExpanded();
this.gcMain.DataSource = dataSet.Tables[0];
this.gcMain.DataSource = resultTable;
this.SetAutoColumns();
//根据记录展开对应节点
foreach (TreeListNode treeListNode in treeListNodes)
@@ -2193,7 +2215,7 @@ namespace Lskj.Control
{
this.TreeListObj.FocusedNode = lastNode;
}
return dataSet.Tables[0] != null ? dataSet.Tables[0].Rows.Count : 0;
return rowCount;
}
+50 -27
View File
@@ -2540,60 +2540,83 @@ namespace Lskj.Control
public override int SetGridViewDataSource(DbDataAdapter adapter, bool selectRowHandler = true)
{
if (adapter == null) return 0;
DbDataAdapter previousAdapter = this.AdapterObj;
if (this.ColumnList == null || this.ColumnList.Count == 0)
{
this.TreeListObj.Columns.Clear();
}
lastNodeIndex = 0;
if (selectRowHandler) lastNodeIndex = this.TreeListObj.GetVisibleIndexByNode(this.TreeListObj.FocusedNode);
this.AdapterObj = adapter;
DataSet dataSet = new DataSet();
//adapter.Fill(dataSet, "SetGridViewDataSource");
// 重连配置
int maxRetryCount = 2; // 次数
int retryDelay = 1000; // 等待时间
for (int i = 0; i < maxRetryCount; i++)
try
{
try
for (int i = 0; i < maxRetryCount; i++)
{
adapter.Fill(dataSet, "SetGridViewDataSource");
break;//连接成功
}
catch (SqlException ex)
{
// 判断是否是连接相关错误
if (IsConnectionError(ex.Number) ||
ex.Message.Contains("物理连接不可用") ||
ex.Message.Contains("传输级错误"))
try
{
if (i < maxRetryCount - 1)
adapter.Fill(dataSet, "SetGridViewDataSource");
break;//连接成功
}
catch (SqlException ex)
{
// 判断是否是连接相关错误
if (IsConnectionError(ex.Number) ||
ex.Message.Contains("物理连接不可用") ||
ex.Message.Contains("传输级错误"))
{
SqlConnection.ClearAllPools();
System.Threading.Thread.Sleep(retryDelay);
continue; // 重试
if (i < maxRetryCount - 1)
{
SqlConnection.ClearAllPools();
System.Threading.Thread.Sleep(retryDelay);
continue; // 重试
}
else
{
// 最后一次重试失败,抛出错误
throw new Exception($"经过 {maxRetryCount} 次重试后仍无法连接到数据库: {ex.Message}", ex);
}
}
else
{
// 最后一次重试失败,抛出错误
throw new Exception($"经过 {maxRetryCount} 次重试后仍无法连接到数据库: {ex.Message}", ex);
// 其他SQL错误直接抛出
throw;
}
}
else
{
// 其他SQL错误直接抛出
throw;
}
}
}
DbCommandBuilder cb = SqlHelper.dbFactory.CreateCommandBuilder();
cb.DataAdapter = this.AdapterObj;
catch
{
dataSet.Dispose();
DisposeDataAdapter(adapter);
throw;
}
DataTable resultTable = dataSet.Tables.Count > 0 ? dataSet.Tables[0] : null;
int rowCount = resultTable == null ? 0 : resultTable.Rows.Count;
if (resultTable != null)
{
dataSet.Tables.Remove(resultTable);
}
dataSet.Dispose();
DisposeAdapterCommandBuilder();
if (previousAdapter != null && !ReferenceEquals(previousAdapter, adapter))
{
DisposeDataAdapter(previousAdapter);
}
this.AdapterObj = adapter;
SetAdapterCommandBuilder(this.AdapterObj);
//SqlCommandBuilder cb = new SqlCommandBuilder(this.AdapterObj);
GetTreeExpanded();
this.TreeListObj.DataSource = dataSet.Tables[0];
this.TreeListObj.DataSource = resultTable;
this.AdjustIndicatorWidthSmart();
this.SetAutoColumns();
@@ -2609,7 +2632,7 @@ namespace Lskj.Control
{
this.TreeListObj.CollapseAll();
}
return dataSet.Tables[0] != null ? dataSet.Tables[0].Rows.Count : 0;
return rowCount;
}
+22 -7
View File
@@ -185,7 +185,18 @@ namespace Lskj.Main
{
if (_cefInitialized)
{
CefRuntime.Shutdown();
bool browsersClosed =
CefBrowserRuntimeLifetime.CloseAllBrowsersAndWait(5000);
if (browsersClosed)
{
CefRuntime.Shutdown();
}
else
{
LogHelper.Instance.WriteLog(
"[CEF_LIFECYCLE] CefRuntime.Shutdown skipped " +
"because browser close callbacks are incomplete.");
}
_cefInitialized = false;
}
_mainProcessInitialized = false;
@@ -234,14 +245,18 @@ namespace Lskj.Main
commandLine.AppendSwitch("ignore-certificate-errors", "1");
commandLine.AppendSwitch("allow-running-insecure-content", "1");
//如果注册表中CefMultithreading不为1,并且根目录中不存在BrowserMultithreading.txt"文件,就是单线程模式
//只要有一个条件满足就是多线程模式
if (!BrowserMultithreading() && !File.Exists(PubUtil.AbsolutelyPath + "BrowserMultithreading.txt"))
{
commandLine.AppendSwitch("single-process", "1");//单线程模式,默认开启。(开启单线程模式后会影响浏览器的性能)
}
// CEF's single-process switch is unsupported and is unrelated
// to MultiThreadedMessageLoop. Keep renderer and utility work
// in CEF's normal child processes, as in the official sample.
commandLine.AppendSwitch("no-proxy-server");
// CEF 87 can terminate the host with STATUS_WX86_BREAKPOINT
// while creating the first browser on machines whose GPU
// driver does not support the legacy compositor path. Keep
// software rendering enabled, but bypass GPU initialization.
commandLine.AppendSwitch("disable-gpu");
commandLine.AppendSwitch("disable-gpu-compositing");
commandLine.AppendSwitch("disable-features", "VizDisplayCompositor");
commandLine.AppendSwitch("ppapi-flash-version", "99.0.0.999");
commandLine.AppendSwitch("ppapi-flash-path", @"PepperFlash\pepflashplayer.dll");
//}
@@ -13,9 +13,13 @@
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
if (disposing)
{
components.Dispose();
ReleaseResourcesForDispose();
if (components != null)
{
components.Dispose();
}
}
base.Dispose(disposing);
}
@@ -767,4 +771,4 @@
private DevExpress.XtraBars.PopupMenu pmFP;
private DevExpress.XtraBars.BarManager barManager2;
}
}
}
@@ -48,6 +48,55 @@ namespace Lskj.PubAccraditation
{
InitializeComponent();
}
private void ReleaseResourcesForDispose()
{
if (mResourcesReleased)
{
return;
}
mResourcesReleased = true;
PrintUtil.OnAfterPrint -= OnReportPrintAfter;
MyControl control = ControlObj;
ControlObj = null;
if (control != null)
{
control.OnDataSourceBindCallBack -=
OnControlObjOnDataSourceBindCallBack;
control.OnDataFileRefrshCallBack -= OnDataFileRefrshFile;
control.Dispose();
}
try
{
if (gridBillInfo != null)
{
TreeGridControlEx treeGrid =
gridBillInfo as TreeGridControlEx;
if (treeGrid != null)
{
treeGrid.OnDataSourceBindCallBack -=
OnGridBillInfoOnDataSourceBindCallBack;
}
else
{
gridBillInfo.OnDataSourceBindCallBack -=
OnGridBillInfoOnDataSourceBindCallBack;
}
gridBillInfo.ParentControl = null;
}
if (SysModel != null && SysModel.DataCaches != null)
{
SysModel.DataCaches.Remove(this);
}
}
catch
{
// A partially disposed child must not stop form cleanup.
}
}
#region
/// <summary>
@@ -70,6 +119,7 @@ namespace Lskj.PubAccraditation
/// 主表控件
/// </summary>
public MyControl ControlObj;
private bool mResourcesReleased;
/// <summary>
/// 是否是Brp模块加载审核明细
/// </summary>
@@ -385,16 +435,6 @@ namespace Lskj.PubAccraditation
{
return BaseModuleImpl.GetControlLocation(billAuditModelTask.Result.FormKey, dynamicModel.ModuleCode);
}));
Task<MyControl> controlObjTask = cachesDic.AddTask(this, "ControlObj", new Task<MyControl>(() =>
{
MyControl myControl = new MyControl();
myControl.Model = SysModel;
myControl.PrimaryValue = dynamicModel.BillDocumentId;
cachesDic.AddTask(myControl, "DynamicModel", dynamicModelTask);
cachesDic.AddTask(myControl, "ControlsTable", controlLocationTask);
myControl.GetControlDataCaches(cachesDic);
return myControl;
}));
Task<DataTable> detailColumnsTask = cachesDic.AddTask(gridBillInfo, "DetailColumns", new Task<DataTable>(() =>
{
return BillImpl.GetDetailColumns(dynamicModel.ModuleCode);
@@ -980,14 +1020,26 @@ namespace Lskj.PubAccraditation
{
Dictionary<object, Hashtable> dataCaches = SysModel != null ? SysModel.DataCaches : null;
// 初始化表头
bool controlCreated = false;
if (!dataCaches.GetValue(this, "ControlObj", out this.ControlObj))
{
this.ControlObj = new MyControl();
controlCreated = true;
}
if (!dataCaches.GetValue(this, "ControlLocation", out DataTable dtControlLocation))
{
dtControlLocation = BaseModuleImpl.GetControlLocation(this.BillModelObj.FormKey, this.SysModel.ModuleCode);
}
if (controlCreated && dataCaches != null)
{
DynamicModel controlModel = SysModel;
DataTable controlsTable = dtControlLocation;
dataCaches.AddTask(ControlObj, "DynamicModel",
new Task<DynamicModel>(() => controlModel));
dataCaches.AddTask(ControlObj, "ControlsTable",
new Task<DataTable>(() => controlsTable));
ControlObj.GetControlDataCaches(dataCaches);
}
this.ControlObj.PrimaryValue = this.SysModel.BillDocumentId;
this.ControlObj.isAuditMain = true;
this.ControlObj.InitControl(dtControlLocation, this.pl_left_top);
+151
View File
@@ -26,6 +26,7 @@ using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
@@ -89,6 +90,7 @@ namespace Lskj.PubBill
/// </summary>
private DataTable _detailColumns;
private bool IsCopying = false;
private bool _moduleResourcesReleased;
protected DataRow BillRowItem;
@@ -260,6 +262,155 @@ namespace Lskj.PubBill
InitializeComponent();
}
/// <summary>
/// Releases runtime objects created by the bill module. Cleanup is
/// idempotent and best-effort so it cannot change the close result.
/// </summary>
public void ReleaseModuleResources()
{
if (_moduleResourcesReleased)
return;
_moduleResourcesReleased = true;
TryRelease(() => PrintUtil.OnAfterPrint -= new EventHandler(OnReportPrintAfter), "打印回调");
TryRelease(ReleaseModuleEvents, "模块事件");
TryRelease(ReleaseModuleDataSources, "模块数据源");
TryRelease(ReleaseRuntimeCollections, "运行时集合");
BillRowItem = null;
ControlObj = null;
BillModel = null;
SysModel = null;
SumGridColumn = null;
ScanCodeTextEdit = null;
InitialSelectionTab = null;
_imageEdit = null;
_waterMark = null;
_itemImport = null;
_itemImportUpdate = null;
}
private void ReleaseModuleEvents()
{
if (ScanCodeTextEdit != null)
ScanCodeTextEdit.KeyDown -= Text_KeyDown;
if (gcMain != null)
{
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)
{
tb_buttom.OnDetailSaveGridCallBack -= Tab_OnDetailSaveGridCallBack;
tb_buttom.BillDetailRightGridCallBack -= Tab_OnDetailSaveGridCallBack;
tb_buttom.OnRightCallback -= OnButtomRightCallBack;
if (tb_buttom.TabControlObj != null)
tb_buttom.TabControlObj.SelectedPageChanged -= TabControlObj_SelectedPageChanged;
}
}
private void ReleaseModuleDataSources()
{
foreach (System.Windows.Forms.Control control in EnumerateChildControls(this).ToList())
{
GridControlEx grid = control as GridControlEx;
if (grid != null)
{
TreeGridControlEx treeGrid = grid as TreeGridControlEx;
if (treeGrid != null && treeGrid.TreeListObj != null)
treeGrid.TreeListObj.DataSource = null;
if (grid.GridControl != null)
grid.GridControl.DataSource = null;
}
XtraTabPage tabPage = control as XtraTabPage;
if (tabPage != null)
tabPage.Tag = null;
}
if (_imageEdit != null && _imageEdit.TextEdit != null)
_imageEdit.TextEdit.Image = null;
if (cb_input != null)
cb_input.Properties.Items.Clear();
if (cb_templete != null)
cb_templete.Properties.Items.Clear();
}
private static IEnumerable<System.Windows.Forms.Control> EnumerateChildControls(
System.Windows.Forms.Control root)
{
if (root == null)
yield break;
yield return root;
foreach (System.Windows.Forms.Control child in root.Controls)
foreach (System.Windows.Forms.Control nested in EnumerateChildControls(child))
yield return nested;
}
private void ReleaseRuntimeCollections()
{
foreach (BillModuleModel model in BillModuleModelDic.Values.ToList())
{
if (model == null)
continue;
model.SourceControl = null;
model.SourceDetailControl = null;
model.SourceDetailDetailControl = null;
model.SourceModel = null;
}
BillModuleModelDic.Clear();
pageNumKey.Clear();
foreach (Dictionary<int, DataRow> rows in ToWithdrawRows)
if (rows != null)
rows.Clear();
ToWithdrawRows.Clear();
ChangeColorRow.Clear();
DateColumnList.Clear();
itemCommonList.Clear();
ColorHandles.Clear();
if (DetailMappingField != null)
DetailMappingField.Clear();
if (_printSaveParams != null)
_printSaveParams.Clear();
if (_detailColumns != null)
{
_detailColumns.Dispose();
_detailColumns = null;
}
if (SaveCondTab != null)
{
SaveCondTab.Dispose();
SaveCondTab = null;
}
}
private static void TryRelease(Action release, string operation)
{
try
{
release();
}
catch (Exception exception)
{
Debug.WriteLine("释放单据模块资源失败[" + operation + "]" + exception);
}
}
#region
/// <summary>
/// <para>说明:窗口加载</para>
+17 -1
View File
@@ -209,5 +209,21 @@ namespace Lskj.PubBill
}
}
protected override void OnFormClosed(FormClosedEventArgs e)
{
base.OnFormClosed(e);
this.FormClosing -= OnClose;
this.Activated -= FrmMain_Activated;
try
{
if (billModule1 != null)
billModule1.ReleaseModuleResources();
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine("释放单据窗口资源失败:" + ex);
}
}
}
}
}
+24 -1
View File
@@ -33,7 +33,30 @@ namespace Lskj.PubBrower
this.SubForm = main;
this.SubForm.Text = moduleModel.FormText;
main.PubBrowerModel = moduleModel;
main.OnLoad();
// CEF must be created after the caller has established the final
// WinForms owner/parent hierarchy and the form HWND exists.
if (moduleModel.downLoadFlag == 1)
{
main.OnLoad();
}
else
{
EventHandler shown = null;
shown = delegate
{
main.Shown -= shown;
try
{
main.OnLoad();
}
catch (Exception ex)
{
LogUtil.WriteError("Lskj.PubBrower.dll--初始化错误-->" + obj.ToString(), ex);
}
};
main.Shown += shown;
}
}
catch (Exception ex)
{
+1 -1
View File
@@ -100,8 +100,8 @@ namespace Lskj.PubBrower
previewFrm previewFrm = new previewFrm();
previewFrm.moduleWebView.PubBrowerModel = this.PubBrowerModel;
previewFrm.Dock = DockStyle.Fill;
previewFrm.OnLoad(url, RightKeyFlag);
this.Controls.Add(previewFrm);
previewFrm.OnLoad(url, RightKeyFlag);
}
}
catch (Exception ex)
-14
View File
@@ -16,7 +16,6 @@ namespace Lskj.PubBrower
public previewFrm()
{
InitializeComponent();
this.SizeChanged += OnSizeChanged;
}
/// <summary>
/// <para>说明:窗口加载</para>
@@ -48,18 +47,5 @@ namespace Lskj.PubBrower
MessageUtil.Show(Message, ex.Message);
}
}
/// <summary>
/// 窗体大小改变时
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnSizeChanged(object sender, EventArgs e)
{
if (this.moduleWebView.cefBrowserSettings != null)
{
var handle = this.moduleWebView.cefBrowserSettings.GetHost().GetWindowHandle();
this.moduleWebView.ResizeWindow(handle, this.Width, this.Height);
}
}
}
}
+24 -1
View File
@@ -33,7 +33,30 @@ namespace Lskj.PubBrower2
this.SubForm = main;
this.SubForm.Text = moduleModel.FormText;
main.PubBrowerModel = moduleModel;
main.OnLoad();
// CEF must be created after the caller has established the final
// WinForms owner/parent hierarchy and the form HWND exists.
if (moduleModel.downLoadFlag == 1)
{
main.OnLoad();
}
else
{
EventHandler shown = null;
shown = delegate
{
main.Shown -= shown;
try
{
main.OnLoad();
}
catch (Exception ex)
{
LogUtil.WriteError("Lskj.PubBrower2.dll--初始化错误-->" + obj.ToString(), ex);
}
};
main.Shown += shown;
}
}
catch (Exception ex)
{
+1 -1
View File
@@ -95,8 +95,8 @@ namespace Lskj.PubBrower2
previewFrm previewFrm = new previewFrm();
previewFrm.moduleWebView.PubBrowerModel = this.PubBrowerModel;
previewFrm.Dock = DockStyle.Fill;
previewFrm.OnLoad(url, RightKeyFlag);
this.Controls.Add(previewFrm);
previewFrm.OnLoad(url, RightKeyFlag);
}
}
-14
View File
@@ -16,7 +16,6 @@ namespace Lskj.PubBrower2
public previewFrm()
{
InitializeComponent();
this.SizeChanged += OnSizeChanged;
}
/// <summary>
/// <para>说明:窗口加载</para>
@@ -49,18 +48,5 @@ namespace Lskj.PubBrower2
}
}
/// <summary>
/// 窗体大小改变时
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnSizeChanged(object sender, EventArgs e)
{
if (this.moduleWebView.cefBrowserSettings != null)
{
var handle = this.moduleWebView.cefBrowserSettings.GetHost().GetWindowHandle();
this.moduleWebView.ResizeWindow(handle, this.Width, this.Height);
}
}
}
}
+6 -2
View File
@@ -13,9 +13,13 @@
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
if (disposing)
{
components.Dispose();
ReleaseResourcesForDispose();
if (components != null)
{
components.Dispose();
}
}
base.Dispose(disposing);
}
@@ -25,6 +25,24 @@ namespace Lskj.PubModelAdd
{
InitializeComponent();
}
private void ReleaseResourcesForDispose()
{
if (mResourcesReleased)
{
return;
}
mResourcesReleased = true;
MyControl search = _leftGridSearchObj;
_leftGridSearchObj = null;
if (search != null)
{
search.OnDataSourceBindCallBack -=
OnLeftControlObjDataSourceBindCallBack;
search.Dispose();
}
}
#region
/// <summary>
/// 模块初始化完成
@@ -42,6 +60,7 @@ namespace Lskj.PubModelAdd
/// 左侧表格查询条件
/// </summary>
private MyControl _leftGridSearchObj;
private bool mResourcesReleased;
#endregion
#region
/// <summary>
+6 -2
View File
@@ -13,9 +13,13 @@
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
if (disposing)
{
components.Dispose();
ReleaseResourcesForDispose();
if (components != null)
{
components.Dispose();
}
}
base.Dispose(disposing);
}
@@ -28,6 +28,24 @@ namespace Lskj.PubModelAdd2
{
InitializeComponent();
}
private void ReleaseResourcesForDispose()
{
if (mResourcesReleased)
{
return;
}
mResourcesReleased = true;
MyControl search = _leftGridSearchObj;
_leftGridSearchObj = null;
if (search != null)
{
search.OnDataSourceBindCallBack -=
OnLeftControlObjDataSourceBindCallBack;
search.Dispose();
}
}
#region
/// <summary>
/// 模块初始化完成
@@ -45,6 +63,7 @@ namespace Lskj.PubModelAdd2
/// 左侧表格查询条件
/// </summary>
private MyControl _leftGridSearchObj;
private bool mResourcesReleased;
#endregion
#region
/// <summary>
+6 -2
View File
@@ -13,9 +13,13 @@
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
if (disposing)
{
components.Dispose();
ReleaseResourcesForDispose();
if (components != null)
{
components.Dispose();
}
}
base.Dispose(disposing);
}
@@ -28,6 +28,24 @@ namespace Lskj.PubModelAdd3
{
InitializeComponent();
}
private void ReleaseResourcesForDispose()
{
if (mResourcesReleased)
{
return;
}
mResourcesReleased = true;
MyControl search = _leftGridSearchObj;
_leftGridSearchObj = null;
if (search != null)
{
search.OnDataSourceBindCallBack -=
OnLeftControlObjDataSourceBindCallBack;
search.Dispose();
}
}
#region
/// <summary>
/// 模块初始化完成
@@ -45,6 +63,7 @@ namespace Lskj.PubModelAdd3
/// 左侧表格查询条件
/// </summary>
private MyControl _leftGridSearchObj;
private bool mResourcesReleased;
#endregion
#region
/// <summary>
+7 -3
View File
@@ -13,9 +13,13 @@
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
if (disposing)
{
components.Dispose();
ReleaseResourcesForDispose();
if (components != null)
{
components.Dispose();
}
}
base.Dispose(disposing);
}
@@ -280,4 +284,4 @@
private DevExpress.XtraEditors.SimpleButton btnShowAll;
private DevExpress.XtraEditors.SimpleButton btnRefresh;
}
}
}
+15 -3
View File
@@ -41,6 +41,7 @@ namespace Lskj.PubSpec2
/// 表格列
/// </summary>
private DataTable _gridColumns;
private GridDragTree _dragTree;
/// <summary>
/// 模块对象
@@ -56,6 +57,17 @@ namespace Lskj.PubSpec2
InitializeComponent();
}
private void ReleaseResourcesForDispose()
{
GridDragTree dragTree = _dragTree;
_dragTree = null;
if (dragTree != null)
{
dragTree.OnDragComplete -= OnDragCompleted;
dragTree.Dispose();
}
}
/// <summary>
/// <para>说明:窗口加载</para>
/// <para>创建人:龚宇超</para>
@@ -229,9 +241,9 @@ namespace Lskj.PubSpec2
this.gcMain.Model = this.Model;
this._gridColumns = BaseModuleImpl.GetBaseGridColumns(this.Model.ModuleCode);
GridDragTree dragTree = new GridDragTree(this.gcMain.GridView, this.treeLeft.TreeView);
dragTree.CanDragParentNode = true;
dragTree.OnDragComplete += new GridDragTreeCompleteEventHandler(OnDragCompleted);
this._dragTree = new GridDragTree(this.gcMain.GridView, this.treeLeft.TreeView);
this._dragTree.CanDragParentNode = true;
this._dragTree.OnDragComplete += new GridDragTreeCompleteEventHandler(OnDragCompleted);
this.gcMain.IsSpecModel = true;
this.gcMain.SetEditColumns(this._gridColumns);
+6 -2
View File
@@ -13,9 +13,13 @@
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
if (disposing)
{
components.Dispose();
DisposeReportGridViews();
if (components != null)
{
components.Dispose();
}
}
base.Dispose(disposing);
}
+576
View File
@@ -24,6 +24,8 @@ using Lskj.Business.Impl;
using Lskj.Business;
using System.Threading.Tasks;
using System.Collections;
using System.IO;
using System.Reflection;
namespace Lskj.Report
{
@@ -34,9 +36,19 @@ namespace Lskj.Report
/// </summary>
public DynamicReportModel Model;
private readonly HashSet<DevExpress.XtraGrid.Views.Base.BaseView>
mPreexistingGridLocalizerViews = CaptureGridLocalizerViews();
private readonly HashSet<DevExpress.XtraGrid.Views.Base.BaseView>
mReportGridLocalizerViews =
new HashSet<DevExpress.XtraGrid.Views.Base.BaseView>();
private bool mReportGridResourcesReleased;
private int mDisposedReportGridViewCount;
private int mRemovedGridLocalizerHandlerCount;
public FrmMain()
{
InitializeComponent();
this.Disposed += OnFrmMainDisposed;
}
/// <summary>
@@ -66,6 +78,7 @@ namespace Lskj.Report
this.mControl.Details = details;
this.mControl.InitControls(Model);
CaptureReportGridLocalizerViews();
this.FormClosing += new FormClosingEventHandler(OnClose);
}
catch (Exception ex)
@@ -86,7 +99,570 @@ namespace Lskj.Report
private void OnClose(object sender, FormClosingEventArgs e)
{
WriteReportLifecycleDiagnostics("closing-before-close-module");
this.mControl.CloseModule();
WriteReportLifecycleDiagnostics("closing-after-close-module");
}
private void OnFrmMainDisposed(object sender, EventArgs e)
{
DisposeReportGridViews();
WriteReportLifecycleDiagnostics(
"disposed-event;disposedGridViews=" +
mDisposedReportGridViewCount +
";gridLocalizerRemoved=" +
mRemovedGridLocalizerHandlerCount);
mReportGridLocalizerViews.Clear();
mPreexistingGridLocalizerViews.Clear();
this.FormClosing -= OnClose;
this.Disposed -= OnFrmMainDisposed;
DynamicReportModel model = this.Model;
this.Model = null;
if (model == null || model.DataCaches == null)
{
return;
}
try
{
model.DataCaches.Clear();
}
catch (Exception ex)
{
LogHelper.Instance.WriteError(ex, ResourceKeys.BaseReport);
}
}
private void DisposeReportGridViews()
{
if (mReportGridResourcesReleased)
{
return;
}
mReportGridResourcesReleased = true;
WriteReportLifecycleDiagnostics("dispose-before-gridviews");
CaptureReportGridLocalizerViews();
if (this.mControl != null)
{
this.mControl.ReleaseResourcesForDispose();
}
HashSet<DevExpress.XtraGrid.Views.Base.BaseView> disposedViews =
new HashSet<DevExpress.XtraGrid.Views.Base.BaseView>();
int disposeErrorCount = 0;
int detachedDataSourceCount = 0;
foreach (System.Windows.Forms.Control control in
EnumerateControls(this.mControl))
{
DevExpress.XtraGrid.GridControl gridControl =
control as DevExpress.XtraGrid.GridControl;
if (gridControl != null)
{
try
{
if (gridControl.DataSource != null)
{
gridControl.DataSource = null;
detachedDataSourceCount++;
}
}
catch (Exception ex)
{
disposeErrorCount++;
LogHelper.Instance.WriteError(ex, ResourceKeys.BaseReport);
}
DevExpress.XtraGrid.Views.Base.BaseView[] views =
gridControl.ViewCollection
.Cast<DevExpress.XtraGrid.Views.Base.BaseView>()
.ToArray();
foreach (DevExpress.XtraGrid.Views.Base.BaseView view in views)
{
if (view == null || !disposedViews.Add(view))
{
continue;
}
try
{
view.Dispose();
}
catch (Exception ex)
{
disposeErrorCount++;
LogHelper.Instance.WriteError(ex, ResourceKeys.BaseReport);
}
}
}
Type controlType = control.GetType();
if (controlType.FullName != null &&
controlType.FullName.StartsWith(
"DevExpress.XtraTreeList.",
StringComparison.Ordinal))
{
try
{
PropertyInfo dataSourceProperty =
controlType.GetProperty(
"DataSource",
BindingFlags.Instance |
BindingFlags.Public);
if (dataSourceProperty != null &&
dataSourceProperty.CanRead &&
dataSourceProperty.CanWrite &&
dataSourceProperty.GetValue(control, null) != null)
{
dataSourceProperty.SetValue(control, null, null);
detachedDataSourceCount++;
}
}
catch (Exception ex)
{
disposeErrorCount++;
LogHelper.Instance.WriteError(ex, ResourceKeys.BaseReport);
}
}
}
int trackedGridViews = mReportGridLocalizerViews.Count;
int removedGridLocalizerHandlers =
ReleaseTrackedGridLocalizerViews(disposedViews);
mDisposedReportGridViewCount = disposedViews.Count;
mRemovedGridLocalizerHandlerCount = removedGridLocalizerHandlers;
WriteReportLifecycleDiagnostics(
"dispose-after-gridviews;dispose-attempts=" +
disposedViews.Count +
";dispose-errors=" +
disposeErrorCount +
";detachedDataSources=" +
detachedDataSourceCount +
";trackedGridViews=" +
trackedGridViews +
";gridLocalizerRemoved=" +
removedGridLocalizerHandlers);
}
private void CaptureReportGridLocalizerViews()
{
HashSet<DevExpress.XtraGrid.Views.Base.BaseView> currentViews =
CaptureGridLocalizerViews();
foreach (DevExpress.XtraGrid.Views.Base.BaseView view in currentViews)
{
if (!mPreexistingGridLocalizerViews.Contains(view))
{
mReportGridLocalizerViews.Add(view);
}
}
}
private int ReleaseTrackedGridLocalizerViews(
HashSet<DevExpress.XtraGrid.Views.Base.BaseView> disposedViews)
{
foreach (DevExpress.XtraGrid.Views.Base.BaseView view in
mReportGridLocalizerViews)
{
if (view == null ||
(disposedViews != null && !disposedViews.Add(view)))
{
continue;
}
try
{
view.Dispose();
}
catch (Exception exception)
{
LogHelper.Instance.WriteError(exception, ResourceKeys.BaseReport);
}
}
return RemoveGridLocalizerHandlers(mReportGridLocalizerViews);
}
private static HashSet<DevExpress.XtraGrid.Views.Base.BaseView>
CaptureGridLocalizerViews()
{
HashSet<DevExpress.XtraGrid.Views.Base.BaseView> result =
new HashSet<DevExpress.XtraGrid.Views.Base.BaseView>();
try
{
var activeLocalizer =
DevExpress.XtraGrid.Localization.GridLocalizer.Active;
if (activeLocalizer == null)
{
return result;
}
Type currentType = activeLocalizer.GetType();
while (currentType != null && currentType != typeof(object))
{
FieldInfo[] fields = currentType.GetFields(
BindingFlags.Instance |
BindingFlags.Static |
BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.DeclaredOnly);
foreach (FieldInfo field in fields)
{
if (!typeof(Delegate).IsAssignableFrom(field.FieldType))
{
continue;
}
object owner = field.IsStatic ? null : (object)activeLocalizer;
Delegate current;
try
{
current = field.GetValue(owner) as Delegate;
}
catch
{
continue;
}
if (current == null)
{
continue;
}
foreach (Delegate handler in current.GetInvocationList())
{
if (IsGridLocalizerHandler(handler))
{
result.Add(
(DevExpress.XtraGrid.Views.Base.BaseView)
handler.Target);
}
}
}
currentType = currentType.BaseType;
}
}
catch
{
// Diagnostics cleanup must never interfere with form construction.
}
return result;
}
private static int RemoveGridLocalizerHandlers(
HashSet<DevExpress.XtraGrid.Views.Base.BaseView> targetViews)
{
if (targetViews == null || targetViews.Count == 0)
{
return 0;
}
int removedCount = 0;
try
{
var activeLocalizer =
DevExpress.XtraGrid.Localization.GridLocalizer.Active;
if (activeLocalizer == null)
{
return 0;
}
Type currentType = activeLocalizer.GetType();
while (currentType != null && currentType != typeof(object))
{
FieldInfo[] fields = currentType.GetFields(
BindingFlags.Instance |
BindingFlags.Static |
BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.DeclaredOnly);
foreach (FieldInfo field in fields)
{
if (!typeof(Delegate).IsAssignableFrom(field.FieldType))
{
continue;
}
object owner = field.IsStatic ? null : (object)activeLocalizer;
Delegate current;
try
{
current = field.GetValue(owner) as Delegate;
}
catch
{
continue;
}
if (current == null)
{
continue;
}
Delegate retained = null;
int fieldRemovedCount = 0;
foreach (Delegate handler in current.GetInvocationList())
{
DevExpress.XtraGrid.Views.Base.BaseView view =
handler.Target as DevExpress.XtraGrid.Views.Base.BaseView;
if (IsGridLocalizerHandler(handler) &&
targetViews.Contains(view))
{
fieldRemovedCount++;
continue;
}
retained = retained == null
? handler
: Delegate.Combine(retained, handler);
}
if (fieldRemovedCount == 0)
{
continue;
}
try
{
field.SetValue(owner, retained);
removedCount += fieldRemovedCount;
}
catch
{
// Some DevExpress versions expose a read-only backing field.
}
}
currentType = currentType.BaseType;
}
}
catch
{
// Diagnostics cleanup must never interfere with form disposal.
}
return removedCount;
}
private static bool IsGridLocalizerHandler(Delegate handler)
{
return handler != null &&
string.Equals(
handler.Method.Name,
"OnLocalizer_Changed",
StringComparison.Ordinal) &&
handler.Target is DevExpress.XtraGrid.Views.Base.BaseView;
}
private void WriteReportLifecycleDiagnostics(string phase)
{
if (!IsReportDiagnosticsEnabled())
{
return;
}
try
{
LogHelper.Instance.WriteLog(
"REPORT_DIAGNOSTIC phase=" +
(phase ?? string.Empty) +
" " +
GetReportGridDiagnostics(),
"ResourceDiagnostics.Report");
}
catch
{
// Diagnostics must never interfere with module close/dispose.
}
}
private string GetReportGridDiagnostics()
{
int controlCount = 0;
int gridControlCount = 0;
int viewCount = 0;
HashSet<DevExpress.XtraGrid.Views.Base.BaseView> views =
new HashSet<DevExpress.XtraGrid.Views.Base.BaseView>();
StringBuilder viewDetails = new StringBuilder();
try
{
if (this.mControl != null)
{
foreach (System.Windows.Forms.Control control in EnumerateControls(this.mControl))
{
controlCount++;
DevExpress.XtraGrid.GridControl gridControl =
control as DevExpress.XtraGrid.GridControl;
if (gridControl == null)
{
continue;
}
gridControlCount++;
foreach (DevExpress.XtraGrid.Views.Base.BaseView view in
gridControl.ViewCollection.Cast<DevExpress.XtraGrid.Views.Base.BaseView>())
{
if (view == null || !views.Add(view))
{
continue;
}
viewCount++;
if (viewDetails.Length < 1800)
{
if (viewDetails.Length > 0)
{
viewDetails.Append(",");
}
viewDetails.Append(SafeViewDescription(view));
}
}
}
}
}
catch (Exception exception)
{
viewDetails.Append(",enumeration-error=");
viewDetails.Append(exception.GetType().Name);
}
return "formDisposed=" +
this.IsDisposed +
";controlCount=" +
controlCount +
";gridControlCount=" +
gridControlCount +
";viewCount=" +
viewCount +
";views=" +
viewDetails +
";gridLocalizer=" +
DescribeGridLocalizer();
}
private static string SafeViewDescription(
DevExpress.XtraGrid.Views.Base.BaseView view)
{
try
{
return view.GetType().FullName +
":" +
(view.Name ?? string.Empty).Replace(";", ",");
}
catch
{
return "<view-description-error>";
}
}
private static string DescribeGridLocalizer()
{
try
{
var active =
DevExpress.XtraGrid.Localization.GridLocalizer.Active;
if (active == null)
{
return "active=null";
}
StringBuilder handlers = new StringBuilder();
int handlerCount = 0;
Type currentType = active.GetType();
while (currentType != null && currentType != typeof(object))
{
FieldInfo[] fields = currentType.GetFields(
BindingFlags.Instance |
BindingFlags.Static |
BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.DeclaredOnly);
foreach (FieldInfo field in fields)
{
if (!typeof(Delegate).IsAssignableFrom(field.FieldType))
{
continue;
}
object owner = field.IsStatic ? null : (object)active;
Delegate value = field.GetValue(owner) as Delegate;
if (value == null)
{
continue;
}
foreach (Delegate handler in value.GetInvocationList())
{
handlerCount++;
if (handlers.Length < 1800)
{
if (handlers.Length > 0)
{
handlers.Append(",");
}
string targetType = handler.Target == null
? "static"
: handler.Target.GetType().FullName;
handlers.Append(field.Name.Replace(";", ","));
handlers.Append("->");
handlers.Append(targetType.Replace(";", ","));
handlers.Append(".");
handlers.Append(handler.Method.Name.Replace(";", ","));
}
}
}
currentType = currentType.BaseType;
}
return "activeType=" +
active.GetType().FullName.Replace(";", ",") +
";handlerCount=" +
handlerCount +
";handlers=" +
handlers;
}
catch (Exception exception)
{
return "localizer-error=" + exception.GetType().Name;
}
}
private static bool IsReportDiagnosticsEnabled()
{
try
{
return File.Exists(
Path.Combine(
AppDomain.CurrentDomain.BaseDirectory,
"Logs",
"ResourceDiagnostics",
"resource-diagnostics.enabled"));
}
catch
{
return false;
}
}
private static IEnumerable<System.Windows.Forms.Control> EnumerateControls(
System.Windows.Forms.Control root)
{
if (root == null)
{
yield break;
}
yield return root;
foreach (System.Windows.Forms.Control child in root.Controls)
{
foreach (System.Windows.Forms.Control nested in EnumerateControls(child))
{
yield return nested;
}
}
}
/// <summary>