diff --git a/插件库/Lskj.Control/AutoGridLookUp/AutoGridLookUp.cs b/插件库/Lskj.Control/AutoGridLookUp/AutoGridLookUp.cs index 5604d45..c78656c 100644 --- a/插件库/Lskj.Control/AutoGridLookUp/AutoGridLookUp.cs +++ b/插件库/Lskj.Control/AutoGridLookUp/AutoGridLookUp.cs @@ -52,6 +52,13 @@ namespace Lskj.Control /// private bool _working = false; private List _queryQueue = new List(); + private LatestValueWorker _queryWorker; + + private sealed class PopupQueryRequest + { + public string SqlValue; + public bool IsNewPopup; + } /// /// The _popup /// @@ -246,9 +253,7 @@ namespace Lskj.Control public void OnAutoPopupShow() { this.CalcPopupLocation(); - Thread queryThread = new Thread(CalcPopupSize); - queryThread.IsBackground = true; - queryThread.Start(Popup); + ThreadPool.QueueUserWorkItem(CalcPopupSize, Popup); //// 在主线程中显示等待对话框,并在后台线程中执行查询和数据绑定 //Task.Run(() => @@ -339,6 +344,7 @@ namespace Lskj.Control public AutoGridLookUp() { InitializePopup(); + _queryWorker = new LatestValueWorker(ExecuteLatestPopupQuery); InitializeEvent(); this.Disposed += OnDisposed; } @@ -390,9 +396,7 @@ namespace Lskj.Control this.ShowPopup(); } - Thread queryThread = new Thread(CalcPopupSize); - queryThread.IsBackground = true; - queryThread.Start(Popup); + ThreadPool.QueueUserWorkItem(CalcPopupSize, Popup); } /// /// 说明:计算弹出控件位置 @@ -600,16 +604,7 @@ namespace Lskj.Control sqlValue = ControlObj.ReplaceControlValue(sourceSql); } - if (!this._working) - { - Thread thread = new Thread(new ParameterizedThreadStart(RefreshPopupDataSource)); - thread.IsBackground = true; - thread.Start(sqlValue); - } - else - { - this._queryQueue.Add(sqlValue); - } + QueuePopupQuery(sqlValue, false); } } @@ -709,9 +704,9 @@ namespace Lskj.Control string sql = MainImpl.GetDefaultValue(this._queryQueue.Last()); sql = ReplaceHelper.ReplaceParam(sql); // 在检索过程中还存在输入数据,则拿最后一次数据在进行匹配一次 - Thread thread = new Thread(new ParameterizedThreadStart(RefreshPopupDataSource)); - thread.IsBackground = true; - thread.Start(sql); + ThreadPool.QueueUserWorkItem( + RefreshPopupDataSource, + sql); this._queryQueue.Clear(); } @@ -1601,17 +1596,75 @@ namespace Lskj.Control } sqlValue = ControlObj.ReplaceControlValue(sourceSql.Replace("#", "")); } - if (!this._working) + QueuePopupQuery(sqlValue, true); + } + } + + private void QueuePopupQuery(string sqlValue, bool isNewPopup) + { + if (_queryWorker == null || IsDisposed || Disposing) + { + return; + } + + _working = true; + if (Popup != null) + { + Popup.LabelObj.Text = "正在筛选数据,请稍后..."; + Popup.BottomPanelObj.Visible = true; + Popup.GridControlObj.DataSourceTable().Clear(); + } + + _queryWorker.Queue(new PopupQueryRequest + { + SqlValue = sqlValue, + IsNewPopup = isNewPopup + }); + } + + private void ExecuteLatestPopupQuery(PopupQueryRequest request, int version) + { + DateTime beginTime = DateTime.Now; + DataTable table = new DataTable(); + + if (request != null && !string.IsNullOrWhiteSpace(request.SqlValue)) + { + try { - Thread thread = new Thread(new ParameterizedThreadStart(RefreshPopupDataSourceNew)); - thread.IsBackground = true; - thread.Start(sqlValue); + table = SqlHelper.ExecuteDataTable(request.SqlValue); } - else + catch { - this._queryQueue.Add(sqlValue); + table = new DataTable(); } } + + DateTime endTime = DateTime.Now; + if (_queryWorker == null || !_queryWorker.IsCurrent(version) || IsDisposed || Disposing || !IsHandleCreated) + { + return; + } + + try + { + BeginInvoke(new MethodInvoker(delegate + { + if (_queryWorker == null || !_queryWorker.IsCurrent(version) || IsDisposed || Disposing || Popup == null) + { + return; + } + + int second = Convert.ToInt32((endTime - beginTime).TotalSeconds); + string tipMsg = "数据筛选完成."; + Popup.LabelObj.Text = second > 0 ? string.Format(tipMsg + "(耗时{0}秒)", second) : tipMsg; + Popup.GridControlObj.DataSource = table; + _working = false; + CalcFormAndGrid(request != null && request.IsNewPopup); + })); + } + catch (InvalidOperationException) + { + } } private void RefreshPopupDataSourceNew(object sqlValue) @@ -1646,9 +1699,9 @@ namespace Lskj.Control if (this._queryQueue.Count > 0) { // 在检索过程中还存在输入数据,则拿最后一次数据在进行匹配一次 - Thread thread = new Thread(new ParameterizedThreadStart(RefreshPopupDataSourceNew)); - thread.IsBackground = true; - thread.Start(this._queryQueue.Last()); + ThreadPool.QueueUserWorkItem( + RefreshPopupDataSourceNew, + this._queryQueue.Last()); this._queryQueue.Clear(); } else @@ -1681,8 +1734,15 @@ namespace Lskj.Control /// private void OnDisposed(object sender, EventArgs e) { + if (_queryWorker != null) + { + _queryWorker.Dispose(); + _queryWorker = null; + } + _working = false; + _queryQueue.Clear(); this._popup?.Dispose(); this._popup = null; } } -} \ No newline at end of file +} diff --git a/插件库/Lskj.Control/AutoGridLookUp/AutoGridRevLookUp.cs b/插件库/Lskj.Control/AutoGridLookUp/AutoGridRevLookUp.cs index cec8873..aea06e1 100644 --- a/插件库/Lskj.Control/AutoGridLookUp/AutoGridRevLookUp.cs +++ b/插件库/Lskj.Control/AutoGridLookUp/AutoGridRevLookUp.cs @@ -46,6 +46,13 @@ namespace Lskj.Control /// private bool _working = false; private List _queryQueue = new List(); + private LatestValueWorker _queryWorker; + + private sealed class PopupQueryRequest + { + public string SqlValue; + public bool IsNewPopup; + } /// /// The _popup /// @@ -318,6 +325,7 @@ namespace Lskj.Control public AutoGridRevLookUp() { InitializePopup(); + _queryWorker = new LatestValueWorker(ExecuteLatestPopupQuery); InitializeEvent(); this.Disposed += OnDisposed; } @@ -360,9 +368,7 @@ namespace Lskj.Control } private void CalcFormAndGrid() { - Thread queryThread = new Thread(CalcPopupSize); - queryThread.IsBackground = true; - queryThread.Start(Popup); + ThreadPool.QueueUserWorkItem(CalcPopupSize, Popup); } /// /// 说明:计算弹出控件位置 @@ -527,16 +533,7 @@ namespace Lskj.Control } sqlValue = ControlObj.ReplaceControlValue(sourceSql.Replace("#", "")); } - if (!this._working) - { - Thread thread = new Thread(new ParameterizedThreadStart(RefreshPopupDataSource)); - thread.IsBackground = true; - thread.Start(sqlValue); - } - else - { - this._queryQueue.Add(sqlValue); - } + QueuePopupQuery(sqlValue, false); } } @@ -627,9 +624,9 @@ namespace Lskj.Control string sql = MainImpl.GetDefaultValue(this._queryQueue.Last()); sql = ReplaceHelper.ReplaceParam(sql); // 在检索过程中还存在输入数据,则拿最后一次数据在进行匹配一次 - Thread thread = new Thread(new ParameterizedThreadStart(RefreshPopupDataSource)); - thread.IsBackground = true; - thread.Start(sql); + ThreadPool.QueueUserWorkItem( + RefreshPopupDataSource, + sql); this._queryQueue.Clear(); } else @@ -1022,15 +1019,23 @@ namespace Lskj.Control /// The instance containing the event data. protected void OnAutoGridLookUpGotFocus(object sender, EventArgs e) { - System.Threading.Thread thread = new Thread(() => + ThreadPool.QueueUserWorkItem(delegate { while (!this.IsSetDataSource) { + if (IsDisposed || Disposing) + { + return; + } + Thread.Sleep(10); + } + if (IsDisposed || Disposing) + { + return; } this.HandPopupSqlValue(this.Text); ShowPopup(); }); - thread.Start(); } /// /// 鼠标单击控件时 @@ -1041,15 +1046,23 @@ namespace Lskj.Control { if (this._popup.Visible == false) { - System.Threading.Thread thread = new Thread(() => + ThreadPool.QueueUserWorkItem(delegate { while (!this.IsSetDataSource) { + if (IsDisposed || Disposing) + { + return; + } + Thread.Sleep(10); + } + if (IsDisposed || Disposing) + { + return; } this.HandPopupSqlValue(this.Text); ShowPopup(); }); - thread.Start(); } } /// @@ -1327,17 +1340,78 @@ namespace Lskj.Control } sqlValue = ControlObj.ReplaceControlValue(sourceSql.Replace("#", "")); } - if (!this._working) + QueuePopupQuery(sqlValue, true); + } + } + + private void QueuePopupQuery(string sqlValue, bool isNewPopup) + { + if (_queryWorker == null || IsDisposed || Disposing) + { + return; + } + + _working = true; + if (Popup != null) + { + Popup.LabelObj.Text = "正在筛选数据,请稍后..."; + Popup.BottomPanelObj.Visible = true; + Popup.GridControlObj.DataSourceTable().Clear(); + } + + _queryWorker.Queue(new PopupQueryRequest + { + SqlValue = sqlValue, + IsNewPopup = isNewPopup + }); + } + + private void ExecuteLatestPopupQuery(PopupQueryRequest request, int version) + { + DateTime beginTime = DateTime.Now; + DataTable table = new DataTable(); + + if (request != null && !string.IsNullOrWhiteSpace(request.SqlValue)) + { + try { - Thread thread = new Thread(new ParameterizedThreadStart(RefreshPopupDataSourceNew)); - thread.IsBackground = true; - thread.Start(sqlValue); + table = SqlHelper.ExecuteDataTable(request.SqlValue); } - else + catch { - this._queryQueue.Add(sqlValue); + table = new DataTable(); } } + + DateTime endTime = DateTime.Now; + if (_queryWorker == null || !_queryWorker.IsCurrent(version) || IsDisposed || Disposing || !IsHandleCreated) + { + return; + } + + try + { + BeginInvoke(new MethodInvoker(delegate + { + if (_queryWorker == null || !_queryWorker.IsCurrent(version) || IsDisposed || Disposing || Popup == null) + { + return; + } + + int second = Convert.ToInt32((endTime - beginTime).TotalSeconds); + string tipMsg = "数据筛选完成."; + Popup.LabelObj.Text = second > 0 ? string.Format(tipMsg + "(耗时{0}秒)", second) : tipMsg; + Popup.GridControlObj.DataSource = table; + _working = false; + if (request != null && !request.IsNewPopup) + { + CalcFormAndGrid(); + } + })); + } + catch (InvalidOperationException) + { + } } private void RefreshPopupDataSourceNew(object sqlValue) { @@ -1372,9 +1446,9 @@ namespace Lskj.Control if (this._queryQueue.Count > 0) { // 在检索过程中还存在输入数据,则拿最后一次数据在进行匹配一次 - Thread thread = new Thread(new ParameterizedThreadStart(RefreshPopupDataSourceNew)); - thread.IsBackground = true; - thread.Start(this._queryQueue.Last()); + ThreadPool.QueueUserWorkItem( + RefreshPopupDataSourceNew, + this._queryQueue.Last()); this._queryQueue.Clear(); } @@ -1419,8 +1493,15 @@ namespace Lskj.Control /// private void OnDisposed(object sender, EventArgs e) { + if (_queryWorker != null) + { + _queryWorker.Dispose(); + _queryWorker = null; + } + _working = false; + _queryQueue.Clear(); this._popup?.Dispose(); this._popup = null; } } -} \ No newline at end of file +} diff --git a/插件库/Lskj.Control/AutoRemarksBoxLookUp/AutoRemarksBoxLookUp.cs b/插件库/Lskj.Control/AutoRemarksBoxLookUp/AutoRemarksBoxLookUp.cs index 838a690..b0a8ce7 100644 --- a/插件库/Lskj.Control/AutoRemarksBoxLookUp/AutoRemarksBoxLookUp.cs +++ b/插件库/Lskj.Control/AutoRemarksBoxLookUp/AutoRemarksBoxLookUp.cs @@ -46,6 +46,13 @@ namespace Lskj.Control /// private bool _working = false; private List _queryQueue = new List(); + private LatestValueWorker _queryWorker; + + private sealed class PopupQueryRequest + { + public string SqlValue; + public bool IsNewPopup; + } /// /// The _popup /// @@ -307,7 +314,9 @@ namespace Lskj.Control { InitializeComponent(); InitializePopup(); + _queryWorker = new LatestValueWorker(ExecuteLatestPopupQuery); InitializeEvent(); + this.Disposed += OnDisposed; //this.Properties.Buttons[0].Kind = DevExpress.XtraEditors.Controls.ButtonPredefines.Down; } @@ -361,9 +370,7 @@ namespace Lskj.Control this.ShowPopup(); } - Thread queryThread = new Thread(CalcPopupSize); - queryThread.IsBackground = true; - queryThread.Start(Popup); + ThreadPool.QueueUserWorkItem(CalcPopupSize, Popup); } /// /// 说明:计算弹出控件位置 @@ -551,16 +558,7 @@ namespace Lskj.Control sqlValue = ControlObj.ReplaceControlValue(sourceSql); } - if (!this._working) - { - Thread thread = new Thread(new ParameterizedThreadStart(RefreshPopupDataSource)); - thread.IsBackground = true; - thread.Start(sqlValue); - } - else - { - this._queryQueue.Add(sqlValue); - } + QueuePopupQuery(sqlValue, false); } } @@ -656,9 +654,9 @@ namespace Lskj.Control string sql = MainImpl.GetDefaultValue(this._queryQueue.Last()); sql = ReplaceHelper.ReplaceParam(sql); // 在检索过程中还存在输入数据,则拿最后一次数据在进行匹配一次 - Thread thread = new Thread(new ParameterizedThreadStart(RefreshPopupDataSource)); - thread.IsBackground = true; - thread.Start(sql); + ThreadPool.QueueUserWorkItem( + RefreshPopupDataSource, + sql); this._queryQueue.Clear(); } @@ -1403,17 +1401,78 @@ namespace Lskj.Control sqlValue = ControlObj.ReplaceControlValue(sourceSql.Replace("#", "")); } - if (!this._working) + QueuePopupQuery(sqlValue, true); + } + } + + private void QueuePopupQuery(string sqlValue, bool isNewPopup) + { + if (_queryWorker == null || IsDisposed || Disposing) + { + return; + } + + _working = true; + if (Popup != null) + { + Popup.LabelObj.Text = "正在筛选数据,请稍后..."; + Popup.BottomPanelObj.Visible = true; + Popup.GridControlObj.DataSourceTable().Clear(); + } + + _queryWorker.Queue(new PopupQueryRequest + { + SqlValue = sqlValue, + IsNewPopup = isNewPopup + }); + } + + private void ExecuteLatestPopupQuery(PopupQueryRequest request, int version) + { + DateTime beginTime = DateTime.Now; + DataTable table = new DataTable(); + + if (request != null && !string.IsNullOrWhiteSpace(request.SqlValue)) + { + try { - Thread thread = new Thread(new ParameterizedThreadStart(RefreshPopupDataSourceNew)); - thread.IsBackground = true; - thread.Start(sqlValue); + table = SqlHelper.ExecuteDataTable(request.SqlValue); } - else + catch { - this._queryQueue.Add(sqlValue); + table = new DataTable(); } } + + DateTime endTime = DateTime.Now; + if (_queryWorker == null || !_queryWorker.IsCurrent(version) || IsDisposed || Disposing || !IsHandleCreated) + { + return; + } + + try + { + BeginInvoke(new MethodInvoker(delegate + { + if (_queryWorker == null || !_queryWorker.IsCurrent(version) || IsDisposed || Disposing || Popup == null) + { + return; + } + + int second = Convert.ToInt32((endTime - beginTime).TotalSeconds); + string tipMsg = "数据筛选完成."; + Popup.LabelObj.Text = second > 0 ? string.Format(tipMsg + "(耗时{0}秒)", second) : tipMsg; + Popup.GridControlObj.DataSource = table; + _working = false; + if (request != null && !request.IsNewPopup) + { + CalcFormAndGrid(); + } + })); + } + catch (InvalidOperationException) + { + } } private void RefreshPopupDataSourceNew(object sqlValue) @@ -1449,9 +1508,9 @@ namespace Lskj.Control if (this._queryQueue.Count > 0) { // 在检索过程中还存在输入数据,则拿最后一次数据在进行匹配一次 - Thread thread = new Thread(new ParameterizedThreadStart(RefreshPopupDataSourceNew)); - thread.IsBackground = true; - thread.Start(this._queryQueue.Last()); + ThreadPool.QueueUserWorkItem( + RefreshPopupDataSourceNew, + this._queryQueue.Last()); this._queryQueue.Clear(); } @@ -1478,5 +1537,21 @@ namespace Lskj.Control } } + + private void OnDisposed(object sender, EventArgs e) + { + if (_queryWorker != null) + { + _queryWorker.Dispose(); + _queryWorker = null; + } + _working = false; + _queryQueue.Clear(); + if (_popup != null) + { + _popup.Dispose(); + _popup = null; + } + } } -} \ No newline at end of file +} diff --git a/插件库/Lskj.Control/ExcelControlEx.Designer.cs b/插件库/Lskj.Control/ExcelControlEx.Designer.cs index f2a8823..01a348a 100644 --- a/插件库/Lskj.Control/ExcelControlEx.Designer.cs +++ b/插件库/Lskj.Control/ExcelControlEx.Designer.cs @@ -28,6 +28,7 @@ /// private void InitializeComponent() { + this.components = new System.ComponentModel.Container(); this.pl_buttom = new DevExpress.XtraEditors.PanelControl(); this.panelControl1 = new DevExpress.XtraEditors.PanelControl(); this.btnAdd = new DevExpress.XtraEditors.SimpleButton(); @@ -35,7 +36,7 @@ this.btnDel = new DevExpress.XtraEditors.SimpleButton(); this.btnSave = new DevExpress.XtraEditors.SimpleButton(); this.spreadsheetControl1 = new DevExpress.XtraSpreadsheet.SpreadsheetControl(); - this.barManager1 = new DevExpress.XtraBars.BarManager(); + this.barManager1 = new DevExpress.XtraBars.BarManager(this.components); this.commonBar1 = new DevExpress.XtraSpreadsheet.UI.CommonBar(); this.spreadsheetCommandBarButtonItem1 = new DevExpress.XtraSpreadsheet.UI.SpreadsheetCommandBarButtonItem(); this.spreadsheetCommandBarButtonItem2 = new DevExpress.XtraSpreadsheet.UI.SpreadsheetCommandBarButtonItem(); @@ -51,6 +52,7 @@ this.barDockControlLeft = new DevExpress.XtraBars.BarDockControl(); this.barDockControlRight = new DevExpress.XtraBars.BarDockControl(); this.spreadsheetBarController1 = new DevExpress.XtraSpreadsheet.UI.SpreadsheetBarController(); + this.components.Add(this.spreadsheetBarController1); ((System.ComponentModel.ISupportInitialize)(this.pl_buttom)).BeginInit(); this.pl_buttom.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.panelControl1)).BeginInit(); diff --git a/插件库/Lskj.Control/FrmGridSift.cs b/插件库/Lskj.Control/FrmGridSift.cs index 5be5403..a7e5a42 100644 --- a/插件库/Lskj.Control/FrmGridSift.cs +++ b/插件库/Lskj.Control/FrmGridSift.cs @@ -1331,15 +1331,17 @@ namespace Lskj.Control /// static int CalcIndicatorBestWidth(DevExpress.XtraGrid.Views.Grid.GridView view) { - Graphics graphics = new System.Windows.Forms.Control().CreateGraphics(); - SizeF sizeF = new SizeF(); int count = view.TopRowIndex + ((DevExpress.XtraGrid.Views.Grid.ViewInfo.GridViewInfo)view.GetViewInfo()).RowsInfo.Count; if (count == 0) { count = 30; } - sizeF = graphics.MeasureString(count.ToString(), view.Appearance.Row.Font); - return Convert.ToInt32(sizeF.Width) + 20; + int textWidth = TextRenderer.MeasureText( + count.ToString(), + view.Appearance.Row.Font, + Size.Empty, + TextFormatFlags.NoPadding | TextFormatFlags.SingleLine).Width; + return textWidth + 20; } /// /// 计算默认的宽度 @@ -1349,16 +1351,18 @@ namespace Lskj.Control static int CalcIndicatorDefaultWidth(DevExpress.XtraGrid.Views.Grid.GridView view) { var grid = view.GridControl; - Graphics graphics = new System.Windows.Forms.Control().CreateGraphics(); - SizeF sizeF = new SizeF(); int rowHeight = 22;//22是Row的估计高度 if (view.RowHeight > 0) { rowHeight = view.RowHeight; } int count = grid != null ? grid.Height / rowHeight : 30; - sizeF = graphics.MeasureString(count.ToString(), view.Appearance.Row.Font); - return Convert.ToInt32(sizeF.Width) + 20; + int textWidth = TextRenderer.MeasureText( + count.ToString(), + view.Appearance.Row.Font, + Size.Empty, + TextFormatFlags.NoPadding | TextFormatFlags.SingleLine).Width; + return textWidth + 20; } #endregion #region 选中行颜色改变 @@ -2156,4 +2160,4 @@ namespace Lskj.Control } } } -} \ No newline at end of file +} diff --git a/插件库/Lskj.Control/GridControlEx.Designer.cs b/插件库/Lskj.Control/GridControlEx.Designer.cs index 580e0c2..2f840ff 100644 --- a/插件库/Lskj.Control/GridControlEx.Designer.cs +++ b/插件库/Lskj.Control/GridControlEx.Designer.cs @@ -13,9 +13,13 @@ /// 如果应释放托管资源,为 true;否则为 false。 protected override void Dispose(bool disposing) { - if (disposing && (components != null)) + if (disposing) { - components.Dispose(); + DisposeGridResources(); + if (components != null) + { + components.Dispose(); + } } base.Dispose(disposing); } diff --git a/插件库/Lskj.Control/GridControlEx.cs b/插件库/Lskj.Control/GridControlEx.cs index 0bda692..c00fc7a 100644 --- a/插件库/Lskj.Control/GridControlEx.cs +++ b/插件库/Lskj.Control/GridControlEx.cs @@ -73,10 +73,6 @@ namespace Lskj.Control /// private bool isFirstVisableCol = true; /// - /// 表格自定义字体 - /// - private System.Drawing.Text.PrivateFontCollection customFont = new System.Drawing.Text.PrivateFontCollection(); - /// /// The _grid enum object /// private HeaderSiftEnum _columnEnumObj; @@ -201,6 +197,13 @@ namespace Lskj.Control protected bool mLoading = false; protected Timer mTimer = new Timer(); + private bool _gridResourcesDisposed; + private const int BarcodeImageCacheLimit = 200; + private readonly Dictionary _barcodeImageCache = + new Dictionary(StringComparer.Ordinal); + private readonly Queue _barcodeImageOrder = new Queue(); + private readonly Dictionary _rightMenuButtonImages = + new Dictionary(StringComparer.OrdinalIgnoreCase); /// /// 配置有数据源的控件对象 /// @@ -299,6 +302,7 @@ namespace Lskj.Control /// 表格列为会计模块 /// private AmountCellRender cellHelper; + private ToolTipController _mainGridToolTipController; /// /// 合并求和时,前一行的内容 /// @@ -524,10 +528,10 @@ namespace Lskj.Control this.gridView.DataSourceChanged += new EventHandler(OnGridDataSourceChanged); cellHelper = new AmountCellRender(this.gridView); //鼠标悬浮提示框 - ToolTipController MainGvTool = new ToolTipController(); - MainGvTool.AutoPopDelay = 1000000;//提示框显示时间 10分钟 - MainGvTool.BeforeShow += new ToolTipControllerBeforeShowEventHandler(MainGvTool_BeforeShow); - this.gridControl.ToolTipController = MainGvTool; + _mainGridToolTipController = new ToolTipController(); + _mainGridToolTipController.AutoPopDelay = 1000000;//提示框显示时间 10分钟 + _mainGridToolTipController.BeforeShow += new ToolTipControllerBeforeShowEventHandler(MainGvTool_BeforeShow); + this.gridControl.ToolTipController = _mainGridToolTipController; //this.gridView.PopupMenuShowing += new PopupMenuShowingEventHandler(OnGridView_PopupMenuShowing);//添加Footer菜单选项 this.gridView.Click += new EventHandler(OnGridView_Click);//点击复制Footer数据信息 if (SystemInfo.Instance.SelectColorHighlight) @@ -556,6 +560,103 @@ namespace Lskj.Control this.gridView.MouseWheel += GridView_MouseWheel; } + private void DisposeGridResources() + { + if (_gridResourcesDisposed) + { + return; + } + + _gridResourcesDisposed = true; + StopColumnSourceTimer(); + if (mTimer != null) + { + mTimer.Dispose(); + mTimer = null; + } + DisposeColumnImageCaches(ColumnList); + DisposeRightMenuButtonImages(); + ClearBarcodeImageCache(); + mControlSourceDic.Clear(); + mControlList.Clear(); + ColumnList.Clear(); + AutoPadDataReleColList.Clear(); + FrozenColumns.Clear(); + ImageList.Clear(); + RepeatedVerificationNames.Clear(); + PromptMessage.Clear(); + if (_mainGridToolTipController != null) + { + _mainGridToolTipController.BeforeShow -= MainGvTool_BeforeShow; + if (gridControl != null) + { + gridControl.ToolTipController = null; + } + _mainGridToolTipController.Dispose(); + _mainGridToolTipController = null; + } + } + + private void PrepareForColumnRebuild() + { + StopColumnSourceTimer(); + DisposeColumnImageCaches(ColumnList); + DisposeRightMenuButtonImages(); + ClearBarcodeImageCache(); + + GridView.Columns.Clear(); + GridView.GroupSummary.Clear(); + GridView.OptionsView.ShowFooter = false; + DisposeRepositoryItems(); + + ColumnList.Clear(); + AutoPadDataReleColList.Clear(); + FrozenColumns.Clear(); + ImageList.Clear(); + RepeatedVerificationNames.Clear(); + PromptMessage.Clear(); + mControlList.Clear(); + mControlSourceDic.Clear(); + isFirstVisableCol = true; + mLoading = false; + } + + private void DisposeRepositoryItems() + { + RepositoryItem[] repositoryItems = gridControl.RepositoryItems + .Cast() + .ToArray(); + gridControl.RepositoryItems.Clear(); + foreach (RepositoryItem repositoryItem in repositoryItems) + { + repositoryItem.Dispose(); + } + } + + private void ScheduleColumnSources() + { + StopColumnSourceTimer(); + if (_gridResourcesDisposed) + { + return; + } + + mLoading = false; + mTimer.Tick += mTimerTick; + mTimer.Start(); + } + + private void StopColumnSourceTimer() + { + if (mTimer == null) + { + return; + } + + mTimer.Stop(); + mTimer.Tick -= mTimerTick; + } + /// /// 保存前反写多表头数据源 @@ -1404,13 +1505,11 @@ namespace Lskj.Control public virtual void SetReadOnlyColumns(DataTable table, string customColumKey = "") { Dictionary dataCaches = Model != null ? Model.DataCaches : null; - this.mLoading = false; this.InitGridColumsTab = table; this.CustomColumKey = customColumKey; this.gridColumnsInitialized = false; - this.GridView.Columns.Clear(); - this.ColumnList.Clear(); this.selectReturnDisplaySourceCache.Clear(); + PrepareForColumnRebuild(); if (table == null) return; this.gridView.BeginUpdate(); for (int i = 0; i < table.Rows.Count; i++) @@ -1499,9 +1598,7 @@ namespace Lskj.Control //this.SetCustomColumns(); this.gridView.EndUpdate(); //延迟加载数据源 - this.mLoading = false; - this.mTimer.Tick += new EventHandler(mTimerTick); - this.mTimer.Start(); + ScheduleColumnSources(); } /// @@ -1517,7 +1614,8 @@ namespace Lskj.Control /// The instance containing the event data. protected void mTimerTick(object sender, EventArgs e) { - if (!mLoading) + StopColumnSourceTimer(); + if (!mLoading && !_gridResourcesDisposed && !IsDisposed) { mLoading = true; try @@ -1537,11 +1635,6 @@ namespace Lskj.Control mControlSourceDic.Clear(); } } - else - { - this.mTimer.Stop(); - this.mTimer.Dispose(); - } } private void SetColumnsSource(bool UpdateColumnRefresh = false) { @@ -1561,7 +1654,10 @@ namespace Lskj.Control { dataTable = BaseImpl.GetDataTableResult(item.SqlSource); } - Application.DoEvents(); + if (_gridResourcesDisposed || IsDisposed) + { + return; + } if (!item.Visible) continue; switch (item.FieldType) { @@ -1687,9 +1783,8 @@ namespace Lskj.Control public virtual void SetReadOnlyColumns(DataTable table, string customColumKey, Font font, DefaultBoolean allSort) { this.CustomColumKey = customColumKey; - this.GridView.Columns.Clear(); - this.ColumnList.Clear(); this.selectReturnDisplaySourceCache.Clear(); + PrepareForColumnRebuild(); if (table == null) return; for (int i = 0; i < table.Rows.Count; i++) { @@ -1763,8 +1858,7 @@ namespace Lskj.Control this.SetCustomColumns(customTable); // 延迟加载数据源 - this.mTimer.Tick += new EventHandler(mTimerTick); - this.mTimer.Start(); + ScheduleColumnSources(); } /// /// 说明:设置可编辑列 @@ -1779,13 +1873,11 @@ namespace Lskj.Control /// 需要显示表格列右键菜单(保存列属性、重置列属性)则传递此值. public virtual void SetEditColumns(DataTable table, string customColumKey = "") { - this.mLoading = false; this.InitGridColumsTab = table; this.CustomColumKey = customColumKey; this.gridColumnsInitialized = false; - this.GridView.Columns.Clear(); - this.ColumnList.Clear(); this.selectReturnDisplaySourceCache.Clear(); + PrepareForColumnRebuild(); if (table == null) return; Console.WriteLine(DateTime.Now); @@ -1924,8 +2016,7 @@ namespace Lskj.Control Console.WriteLine(DateTime.Now); // 延迟加载数据源 - this.mTimer.Tick += new EventHandler(mTimerTick); - this.mTimer.Start(); + ScheduleColumnSources(); } /// @@ -5201,11 +5292,10 @@ namespace Lskj.Control editorButton.Appearance.BackColor = Color.Transparent; if (!string.IsNullOrEmpty(menuModel.IcoName)) { - Image image = null; try { - image = Image.FromFile(Util.PubUtil.GridColumnIco + menuModel.IcoName); - if (image.Width > 30) + Image image = GetRightMenuButtonImage(menuModel.IcoName); + if (image != null && image.Width > 30) { picWidth = image.Width; } @@ -9451,23 +9541,59 @@ namespace Lskj.Control //ItemPictureEdit.NullText = " "; if (ItemPictureEdit != null && !string.IsNullOrWhiteSpace(e.Value + "")) { - BarcodeSettings settings = new BarcodeSettings(); - settings.X = 0.6f;//设置黑白条宽度 - settings.ImageHeight = 40;//设置生成的条码图片高度 - settings.ImageWidth = 100;//设置生成的条码图片宽度 - settings.Type = BarCodeType.Code128; - settings.Data = e.Value + "";//设置条码数据 - settings.ShowTextOnBottom = true;//设置数据文本显示在条码底部*/ - settings.ShowText = true;//设置数据文本显示 - BarCodeGenerator bargenerator = new BarCodeGenerator(settings); - Image barcodeimage = bargenerator.GenerateImage(); - e.Value = barcodeimage; + e.Value = GetOrCreateBarcodeImage(e.Value + ""); } // e.Value = e.Value + ""; e.Handled = true; } + private Image GetOrCreateBarcodeImage(string value) + { + Image image; + if (_barcodeImageCache.TryGetValue(value, out image)) + { + return image; + } + + BarcodeSettings settings = new BarcodeSettings(); + settings.X = 0.6f; + settings.ImageHeight = 40; + settings.ImageWidth = 100; + settings.Type = BarCodeType.Code128; + settings.Data = value; + settings.ShowTextOnBottom = true; + settings.ShowText = true; + BarCodeGenerator barcodeGenerator = new BarCodeGenerator(settings); + image = barcodeGenerator.GenerateImage(); + + while (_barcodeImageOrder.Count >= BarcodeImageCacheLimit) + { + string oldestValue = _barcodeImageOrder.Dequeue(); + Image oldestImage; + if (_barcodeImageCache.TryGetValue(oldestValue, out oldestImage)) + { + _barcodeImageCache.Remove(oldestValue); + oldestImage.Dispose(); + } + } + + _barcodeImageCache[value] = image; + _barcodeImageOrder.Enqueue(value); + return image; + } + + private void ClearBarcodeImageCache() + { + foreach (Image image in _barcodeImageCache.Values) + { + image.Dispose(); + } + + _barcodeImageCache.Clear(); + _barcodeImageOrder.Clear(); + } + @@ -9822,15 +9948,44 @@ namespace Lskj.Control /// private void ClearImage() { - GridColumnCollection gridColumns = this.GridView.Columns; + DisposeColumnImageCaches( + this.GridView.Columns + .Cast() + .Select(column => column.Tag as GridColumnModel)); + ClearBarcodeImageCache(); + } - foreach (GridColumn col in gridColumns) + private static void DisposeColumnImageCaches( + IEnumerable columnModels) + { + if (columnModels == null) { - GridColumnModel model = col.Tag as GridColumnModel; - if (model != null && model.FieldType == ControlType.LabPicUrl) + return; + } + + foreach (GridColumnModel model in columnModels.Where( + item => item != null && item.LabPicUrlImages != null)) + { + foreach (DictionaryEntry entry in model.LabPicUrlImages) { - model.LabPicUrlImages = new Hashtable(); + if (!(entry.Value is KeyValuePair images)) + { + continue; + } + + if (images.Value != null && !ReferenceEquals(images.Key, images.Value)) + { + images.Value.Dispose(); + } + + if (images.Key != null) + { + images.Key.Dispose(); + } } + + model.LabPicUrlImages.Clear(); + model.LabPicUrlImages = null; } } @@ -10461,18 +10616,68 @@ namespace Lskj.Control if (string.IsNullOrEmpty(caption)) return 40; // 空文本默认宽度 - using (Bitmap tempBitmap = new Bitmap(1, 1)) - using (Graphics g = Graphics.FromImage(tempBitmap)) + int textWidth = TextRenderer.MeasureText( + caption, + font, + Size.Empty, + TextFormatFlags.NoPadding | TextFormatFlags.SingleLine).Width; + return Math.Max(textWidth + padding, 40); + } + + private Image GetRightMenuButtonImage(string imageName) + { + if (string.IsNullOrWhiteSpace(imageName)) { - // 测量文本尺寸 - SizeF textSize = g.MeasureString(caption, font); - - // 计算总宽度 = 文本宽度 + 左右边距 - int width = (int)textSize.Width + padding; - - // 确保宽度不小于最小值 - return Math.Max(width, 40); // 最小宽度40像素 + return null; } + + Image image; + if (_rightMenuButtonImages.TryGetValue(imageName, out image)) + { + return image; + } + + string imagePath = Path.Combine(Util.PubUtil.GridColumnIco, imageName); + using (Image sourceImage = Image.FromFile(imagePath)) + { + image = new Bitmap(sourceImage); + } + + _rightMenuButtonImages[imageName] = image; + return image; + } + + private void DisposeRightMenuButtonImages() + { + if (_rightMenuButtonImages.Count == 0) + { + return; + } + + IEnumerable buttonEditors = + gridControl.RepositoryItems.OfType() + .Concat(gridView.Columns.Cast() + .Select(column => column.ColumnEdit) + .OfType()) + .Distinct(); + + foreach (RepositoryItemButtonEdit buttonEditor in buttonEditors) + { + foreach (EditorButton button in buttonEditor.Buttons) + { + if (button.Image != null && _rightMenuButtonImages.Values.Any(image => ReferenceEquals(image, button.Image))) + { + button.Image = null; + } + } + } + + foreach (Image ownedImage in _rightMenuButtonImages.Values) + { + ownedImage.Dispose(); + } + + _rightMenuButtonImages.Clear(); } diff --git a/插件库/Lskj.Control/LabelRemarkEdit.cs b/插件库/Lskj.Control/LabelRemarkEdit.cs index 5a775ca..3c111a4 100644 --- a/插件库/Lskj.Control/LabelRemarkEdit.cs +++ b/插件库/Lskj.Control/LabelRemarkEdit.cs @@ -160,9 +160,11 @@ namespace Lskj.Control } else { - Graphics g = this.lblText.CreateGraphics(); - SizeF sizeF = g.MeasureString(value, this.lblText.Font); - this.plLeft.Width = (int)sizeF.Width + PaddingLeft; + this.plLeft.Width = TextRenderer.MeasureText( + value, + this.lblText.Font, + Size.Empty, + TextFormatFlags.NoPadding | TextFormatFlags.SingleLine).Width + PaddingLeft; } } } diff --git a/插件库/Lskj.Control/LatestValueWorker.cs b/插件库/Lskj.Control/LatestValueWorker.cs new file mode 100644 index 0000000..b16ed3f --- /dev/null +++ b/插件库/Lskj.Control/LatestValueWorker.cs @@ -0,0 +1,117 @@ +using System; +using System.Threading; + +namespace Lskj.Control +{ + /// + /// 串行处理请求,并在繁忙时只保留最后一次请求。 + /// 用于输入联想控件,避免每次 TextChanged 都创建独立线程。 + /// + internal sealed class LatestValueWorker : IDisposable + { + private readonly object _syncRoot = new object(); + private readonly Action _work; + private T _pendingValue; + private bool _hasPendingValue; + private bool _workerRunning; + private bool _disposed; + private int _version; + + public LatestValueWorker(Action work) + { + if (work == null) + { + throw new ArgumentNullException("work"); + } + + _work = work; + } + + public int Queue(T value) + { + bool startWorker = false; + int version; + + lock (_syncRoot) + { + if (_disposed) + { + return -1; + } + + version = ++_version; + _pendingValue = value; + _hasPendingValue = true; + + if (!_workerRunning) + { + _workerRunning = true; + startWorker = true; + } + } + + if (startWorker && !ThreadPool.QueueUserWorkItem(Run)) + { + lock (_syncRoot) + { + _workerRunning = false; + } + + throw new InvalidOperationException("无法启动输入联想查询任务。"); + } + + return version; + } + + public bool IsCurrent(int version) + { + lock (_syncRoot) + { + return !_disposed && version == _version; + } + } + + private void Run(object state) + { + while (true) + { + T value; + int version; + + lock (_syncRoot) + { + if (_disposed || !_hasPendingValue) + { + _workerRunning = false; + return; + } + + value = _pendingValue; + version = _version; + _pendingValue = default(T); + _hasPendingValue = false; + } + + try + { + _work(value, version); + } + catch + { + // 查询异常由控件自身转换为空结果;这里确保工作循环能够继续或退出。 + } + } + } + + public void Dispose() + { + lock (_syncRoot) + { + _disposed = true; + _hasPendingValue = false; + _pendingValue = default(T); + _version++; + } + } + } +} diff --git a/插件库/Lskj.Control/Lskj.Control.csproj b/插件库/Lskj.Control/Lskj.Control.csproj index 4b9f67c..4086ad1 100644 --- a/插件库/Lskj.Control/Lskj.Control.csproj +++ b/插件库/Lskj.Control/Lskj.Control.csproj @@ -712,6 +712,7 @@ UserControl + UserControl diff --git a/插件库/Lskj.Control/Model/BandedGridDragGrid.cs b/插件库/Lskj.Control/Model/BandedGridDragGrid.cs index d5740c3..197fcd6 100644 --- a/插件库/Lskj.Control/Model/BandedGridDragGrid.cs +++ b/插件库/Lskj.Control/Model/BandedGridDragGrid.cs @@ -26,8 +26,9 @@ namespace Lskj.Control.Model /// /// 表格拖拽到表格 /// - public class BandedGridDragGrid + public class BandedGridDragGrid : IDisposable { + private bool _disposed; /// /// 是否正在拖拽 /// @@ -106,6 +107,99 @@ namespace Lskj.Control.Model this._targetGridView.GridControl.DragEnter += new System.Windows.Forms.DragEventHandler(gridControl_DragEnter); this._targetGridView.GridControl.DragDrop += new System.Windows.Forms.DragEventHandler(gridControl_DragDrop); this._targetGridView.GridControl.DragLeave += new EventHandler(gridControl_DragLeave); + this._sourceGridView.Disposed += OnGridViewDisposed; + if (!ReferenceEquals(this._sourceGridView, this._targetGridView)) + { + this._targetGridView.Disposed += OnGridViewDisposed; + } + } + + private void OnGridViewDisposed(object sender, EventArgs e) + { + Dispose(); + } + + public void Dispose() + { + if (_disposed) + { + return; + } + + _disposed = true; + BandedGridView sourceGridView = _sourceGridView; + GridView targetGridView = _targetGridView; + + if (sourceGridView != null) + { + sourceGridView.MouseDown -= sourceGridView_MouseDown; + sourceGridView.MouseMove -= sourceGridView_MouseMove; + sourceGridView.MouseUp -= sourceGridView_MouseUp; + sourceGridView.RowClick -= OnRowClick; + sourceGridView.Disposed -= OnGridViewDisposed; + } + + if (targetGridView != null) + { + if (targetGridView.GridControl != null) + { + targetGridView.GridControl.DragOver -= gridControl_DragOver; + targetGridView.GridControl.DragEnter -= gridControl_DragEnter; + targetGridView.GridControl.DragDrop -= gridControl_DragDrop; + targetGridView.GridControl.DragLeave -= gridControl_DragLeave; + } + + if (!ReferenceEquals(sourceGridView, targetGridView)) + { + targetGridView.Disposed -= OnGridViewDisposed; + } + } + + RemoveRegistration( + StaticBandedControl.BandedGridViewDragGridDic, + sourceGridView, + this); + RemoveRegistration( + StaticBandedControl.BandedTargetViewDragGridDic, + targetGridView, + this); + + if (ReferenceEquals( + StaticBandedControl.SourceDragBandedGridView, + sourceGridView)) + { + StaticBandedControl.SourceDragBandedGridView = null; + } + + OnDragComplete = null; + DragHander.Clear(); + _hitInfo = null; + _sourceGridView = null; + _targetGridView = null; + } + + private static void RemoveRegistration( + Dictionary> registrations, + TKey key, + BandedGridDragGrid registration) + where TKey : class + { + if (key == null) + { + return; + } + + List registrationsForView; + if (!registrations.TryGetValue(key, out registrationsForView)) + { + return; + } + + registrationsForView.Remove(registration); + if (registrationsForView.Count == 0) + { + registrations.Remove(key); + } } /// /// 点击时候判断位置 diff --git a/插件库/Lskj.Control/Model/GridDragGrid.cs b/插件库/Lskj.Control/Model/GridDragGrid.cs index e1ddc67..e517311 100644 --- a/插件库/Lskj.Control/Model/GridDragGrid.cs +++ b/插件库/Lskj.Control/Model/GridDragGrid.cs @@ -29,8 +29,9 @@ namespace Lskj.Control.Model /// /// 表格拖拽到表格 /// - public class GridDragGrid + public class GridDragGrid : IDisposable { + private bool _disposed; /// /// 是否正在拖拽 /// @@ -119,6 +120,97 @@ namespace Lskj.Control.Model this._targetGridView.GridControl.DragEnter += new System.Windows.Forms.DragEventHandler(gridControl_DragEnter); this._targetGridView.GridControl.DragDrop += new System.Windows.Forms.DragEventHandler(gridControl_DragDrop); this._targetGridView.GridControl.DragLeave += new EventHandler(gridControl_DragLeave); + this._sourceGridView.Disposed += OnGridViewDisposed; + if (!ReferenceEquals(this._sourceGridView, this._targetGridView)) + { + this._targetGridView.Disposed += OnGridViewDisposed; + } + } + + private void OnGridViewDisposed(object sender, EventArgs e) + { + Dispose(); + } + + public void Dispose() + { + if (_disposed) + { + return; + } + + _disposed = true; + GridView sourceGridView = _sourceGridView; + GridView targetGridView = _targetGridView; + + if (sourceGridView != null) + { + sourceGridView.MouseDown -= sourceGridView_MouseDown; + sourceGridView.MouseMove -= sourceGridView_MouseMove; + sourceGridView.MouseUp -= sourceGridView_MouseUp; + sourceGridView.RowClick -= OnRowClick; + sourceGridView.Disposed -= OnGridViewDisposed; + } + + if (targetGridView != null) + { + if (targetGridView.GridControl != null) + { + targetGridView.GridControl.DragOver -= gridControl_DragOver; + targetGridView.GridControl.DragEnter -= gridControl_DragEnter; + targetGridView.GridControl.DragDrop -= gridControl_DragDrop; + targetGridView.GridControl.DragLeave -= gridControl_DragLeave; + } + + if (!ReferenceEquals(sourceGridView, targetGridView)) + { + targetGridView.Disposed -= OnGridViewDisposed; + } + } + + RemoveRegistration( + StaticControl.GridViewDragGridDic, + sourceGridView, + this); + RemoveRegistration( + StaticControl.TargetViewDragGridDic, + targetGridView, + this); + + if (ReferenceEquals(StaticControl.SourceDragGridView, sourceGridView)) + { + StaticControl.SourceDragGridView = null; + } + + OnDragComplete = null; + DragHander.Clear(); + _hitInfo = null; + _sourceGridView = null; + _targetGridView = null; + } + + private static void RemoveRegistration( + Dictionary> registrations, + TKey key, + GridDragGrid registration) + where TKey : class + { + if (key == null) + { + return; + } + + List registrationsForView; + if (!registrations.TryGetValue(key, out registrationsForView)) + { + return; + } + + registrationsForView.Remove(registration); + if (registrationsForView.Count == 0) + { + registrations.Remove(key); + } } /// /// 点击时候判断位置 diff --git a/插件库/Lskj.Control/Model/WaitForm.cs b/插件库/Lskj.Control/Model/WaitForm.cs index f630efd..988ff67 100644 --- a/插件库/Lskj.Control/Model/WaitForm.cs +++ b/插件库/Lskj.Control/Model/WaitForm.cs @@ -73,10 +73,23 @@ namespace Lskj.Control.Model /// public static void HideForm() { - bool isSplashFormVisible = LoadForm.IsSplashFormVisible; - if (isSplashFormVisible) + SplashScreenManager manager = _loadForm; + if (manager == null) + return; + + try { - _loadForm.CloseWaitForm(); + if (manager.IsSplashFormVisible) + { + manager.CloseWaitForm(); + manager.WaitForSplashFormClose(); + } + } + finally + { + manager.Dispose(); + if (ReferenceEquals(_loadForm, manager)) + _loadForm = null; } } } diff --git a/插件库/Lskj.Control/ModuleEx.Designer.cs b/插件库/Lskj.Control/ModuleEx.Designer.cs index d36e2bd..66bd75a 100644 --- a/插件库/Lskj.Control/ModuleEx.Designer.cs +++ b/插件库/Lskj.Control/ModuleEx.Designer.cs @@ -28,6 +28,7 @@ /// private void InitializeComponent() { + this.components = new System.ComponentModel.Container(); this.scc_container = new DevExpress.XtraEditors.SplitContainerControl(); this.pl_left = new DevExpress.XtraEditors.PanelControl(); this.pl_left_main = new System.Windows.Forms.Panel(); @@ -38,25 +39,8 @@ this.pl_left_top = new DevExpress.XtraEditors.PanelControl(); this.pl_right = new DevExpress.XtraEditors.PanelControl(); this.moduleGridDetailEx1 = new Lskj.Control.ModuleGridDetailEx(); - this.excelControlEx1 = new Lskj.Control.ExcelControlEx(); this.repModelDetailEx = new Lskj.Control.ReplacementDetailEx(); this.MainBodyTab = new DevExpress.XtraTab.XtraTabControl(); - this.barManager1 = new DevExpress.XtraBars.BarManager(); - this.barDockControlTop = new DevExpress.XtraBars.BarDockControl(); - this.barDockControlBottom = new DevExpress.XtraBars.BarDockControl(); - this.barDockControlLeft = new DevExpress.XtraBars.BarDockControl(); - this.barDockControlRight = new DevExpress.XtraBars.BarDockControl(); - this.commonBar1 = new DevExpress.XtraSpreadsheet.UI.CommonBar(); - this.spreadsheetCommandBarButtonItem1 = new DevExpress.XtraSpreadsheet.UI.SpreadsheetCommandBarButtonItem(); - this.spreadsheetCommandBarButtonItem2 = new DevExpress.XtraSpreadsheet.UI.SpreadsheetCommandBarButtonItem(); - this.spreadsheetCommandBarButtonItem3 = new DevExpress.XtraSpreadsheet.UI.SpreadsheetCommandBarButtonItem(); - this.spreadsheetCommandBarButtonItem4 = new DevExpress.XtraSpreadsheet.UI.SpreadsheetCommandBarButtonItem(); - this.spreadsheetCommandBarButtonItem5 = new DevExpress.XtraSpreadsheet.UI.SpreadsheetCommandBarButtonItem(); - this.spreadsheetCommandBarButtonItem6 = new DevExpress.XtraSpreadsheet.UI.SpreadsheetCommandBarButtonItem(); - this.spreadsheetCommandBarButtonItem7 = new DevExpress.XtraSpreadsheet.UI.SpreadsheetCommandBarButtonItem(); - this.spreadsheetCommandBarButtonItem8 = new DevExpress.XtraSpreadsheet.UI.SpreadsheetCommandBarButtonItem(); - this.spreadsheetCommandBarButtonItem9 = new DevExpress.XtraSpreadsheet.UI.SpreadsheetCommandBarButtonItem(); - this.spreadsheetBarController1 = new DevExpress.XtraSpreadsheet.UI.SpreadsheetBarController(); ((System.ComponentModel.ISupportInitialize)(this.scc_container)).BeginInit(); this.scc_container.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.pl_left)).BeginInit(); @@ -68,8 +52,6 @@ ((System.ComponentModel.ISupportInitialize)(this.pl_right)).BeginInit(); this.pl_right.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.MainBodyTab)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.barManager1)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.spreadsheetBarController1)).BeginInit(); this.SuspendLayout(); // // scc_container @@ -172,7 +154,6 @@ // this.pl_right.BorderStyle = DevExpress.XtraEditors.Controls.BorderStyles.NoBorder; this.pl_right.Controls.Add(this.moduleGridDetailEx1); - this.pl_right.Controls.Add(this.excelControlEx1); this.pl_right.Controls.Add(this.repModelDetailEx); this.pl_right.Controls.Add(this.MainBodyTab); this.pl_right.Dock = System.Windows.Forms.DockStyle.Fill; @@ -190,20 +171,6 @@ this.moduleGridDetailEx1.TabIndex = 0; this.moduleGridDetailEx1.VisibleDetailPanel = true; // - // excelControlEx1 - // - this.excelControlEx1.AddEnabled = true; - this.excelControlEx1.DeleteEnabled = true; - this.excelControlEx1.Dock = System.Windows.Forms.DockStyle.Fill; - this.excelControlEx1.Location = new System.Drawing.Point(0, 0); - this.excelControlEx1.Margin = new System.Windows.Forms.Padding(6); - this.excelControlEx1.Name = "excelControlEx1"; - this.excelControlEx1.PrintEnabled = true; - this.excelControlEx1.SaveEnabled = true; - this.excelControlEx1.Size = new System.Drawing.Size(712, 610); - this.excelControlEx1.TabIndex = 1; - this.excelControlEx1.Visible = false; - // // repModelDetailEx // this.repModelDetailEx.Dock = System.Windows.Forms.DockStyle.Fill; @@ -224,147 +191,11 @@ this.MainBodyTab.TabIndex = 6; this.MainBodyTab.Visible = false; // - // barManager1 - // - this.barManager1.DockControls.Add(this.barDockControlTop); - this.barManager1.DockControls.Add(this.barDockControlBottom); - this.barManager1.DockControls.Add(this.barDockControlLeft); - this.barManager1.DockControls.Add(this.barDockControlRight); - this.barManager1.Form = this; - this.barManager1.MaxItemId = 9; - // - // barDockControlTop - // - this.barDockControlTop.CausesValidation = false; - this.barDockControlTop.Dock = System.Windows.Forms.DockStyle.Top; - this.barDockControlTop.Location = new System.Drawing.Point(0, 0); - this.barDockControlTop.Size = new System.Drawing.Size(915, 0); - // - // barDockControlBottom - // - this.barDockControlBottom.CausesValidation = false; - this.barDockControlBottom.Dock = System.Windows.Forms.DockStyle.Bottom; - this.barDockControlBottom.Location = new System.Drawing.Point(0, 610); - this.barDockControlBottom.Size = new System.Drawing.Size(915, 0); - // - // barDockControlLeft - // - this.barDockControlLeft.CausesValidation = false; - this.barDockControlLeft.Dock = System.Windows.Forms.DockStyle.Left; - this.barDockControlLeft.Location = new System.Drawing.Point(0, 0); - this.barDockControlLeft.Size = new System.Drawing.Size(0, 610); - // - // barDockControlRight - // - this.barDockControlRight.CausesValidation = false; - this.barDockControlRight.Dock = System.Windows.Forms.DockStyle.Right; - this.barDockControlRight.Location = new System.Drawing.Point(915, 0); - this.barDockControlRight.Size = new System.Drawing.Size(0, 610); - // - // commonBar1 - // - this.commonBar1.BarName = ""; - this.commonBar1.Control = null; - this.commonBar1.DockCol = 0; - this.commonBar1.DockRow = 0; - this.commonBar1.FloatLocation = new System.Drawing.Point(339, 195); - this.commonBar1.FloatSize = new System.Drawing.Size(244, 31); - this.commonBar1.Offset = 44; - this.commonBar1.Text = ""; - // - // spreadsheetCommandBarButtonItem1 - // - this.spreadsheetCommandBarButtonItem1.Caption = "New"; - this.spreadsheetCommandBarButtonItem1.CommandName = "FileNew"; - this.spreadsheetCommandBarButtonItem1.Enabled = false; - this.spreadsheetCommandBarButtonItem1.Id = 8; - this.spreadsheetCommandBarButtonItem1.Name = "spreadsheetCommandBarButtonItem1"; - // - // spreadsheetCommandBarButtonItem2 - // - this.spreadsheetCommandBarButtonItem2.Caption = "Open"; - this.spreadsheetCommandBarButtonItem2.CommandName = "FileOpen"; - this.spreadsheetCommandBarButtonItem2.Enabled = false; - this.spreadsheetCommandBarButtonItem2.Id = 7; - this.spreadsheetCommandBarButtonItem2.Name = "spreadsheetCommandBarButtonItem2"; - // - // spreadsheetCommandBarButtonItem3 - // - this.spreadsheetCommandBarButtonItem3.Caption = "Save"; - this.spreadsheetCommandBarButtonItem3.CommandName = "FileSave"; - this.spreadsheetCommandBarButtonItem3.Enabled = false; - this.spreadsheetCommandBarButtonItem3.Id = 6; - this.spreadsheetCommandBarButtonItem3.Name = "spreadsheetCommandBarButtonItem3"; - // - // spreadsheetCommandBarButtonItem4 - // - this.spreadsheetCommandBarButtonItem4.Caption = "Save As"; - this.spreadsheetCommandBarButtonItem4.CommandName = "FileSaveAs"; - this.spreadsheetCommandBarButtonItem4.Enabled = false; - this.spreadsheetCommandBarButtonItem4.Id = 5; - this.spreadsheetCommandBarButtonItem4.Name = "spreadsheetCommandBarButtonItem4"; - // - // spreadsheetCommandBarButtonItem5 - // - this.spreadsheetCommandBarButtonItem5.Caption = "&Quick Print"; - this.spreadsheetCommandBarButtonItem5.CommandName = "FileQuickPrint"; - this.spreadsheetCommandBarButtonItem5.Enabled = false; - this.spreadsheetCommandBarButtonItem5.Id = 4; - this.spreadsheetCommandBarButtonItem5.Name = "spreadsheetCommandBarButtonItem5"; - // - // spreadsheetCommandBarButtonItem6 - // - this.spreadsheetCommandBarButtonItem6.Caption = "&Print"; - this.spreadsheetCommandBarButtonItem6.CommandName = "FilePrint"; - this.spreadsheetCommandBarButtonItem6.Enabled = false; - this.spreadsheetCommandBarButtonItem6.Id = 3; - this.spreadsheetCommandBarButtonItem6.Name = "spreadsheetCommandBarButtonItem6"; - // - // spreadsheetCommandBarButtonItem7 - // - this.spreadsheetCommandBarButtonItem7.Caption = "Print Pre&view"; - this.spreadsheetCommandBarButtonItem7.CommandName = "FilePrintPreview"; - this.spreadsheetCommandBarButtonItem7.Enabled = false; - this.spreadsheetCommandBarButtonItem7.Id = 2; - this.spreadsheetCommandBarButtonItem7.Name = "spreadsheetCommandBarButtonItem7"; - // - // spreadsheetCommandBarButtonItem8 - // - this.spreadsheetCommandBarButtonItem8.Caption = "Undo"; - this.spreadsheetCommandBarButtonItem8.CommandName = "FileUndo"; - this.spreadsheetCommandBarButtonItem8.Enabled = false; - this.spreadsheetCommandBarButtonItem8.Id = 1; - this.spreadsheetCommandBarButtonItem8.Name = "spreadsheetCommandBarButtonItem8"; - // - // spreadsheetCommandBarButtonItem9 - // - this.spreadsheetCommandBarButtonItem9.Caption = "Redo"; - this.spreadsheetCommandBarButtonItem9.CommandName = "FileRedo"; - this.spreadsheetCommandBarButtonItem9.Enabled = false; - this.spreadsheetCommandBarButtonItem9.Id = 0; - this.spreadsheetCommandBarButtonItem9.Name = "spreadsheetCommandBarButtonItem9"; - // - // spreadsheetBarController1 - // - this.spreadsheetBarController1.BarItems.Add(this.spreadsheetCommandBarButtonItem1); - this.spreadsheetBarController1.BarItems.Add(this.spreadsheetCommandBarButtonItem2); - this.spreadsheetBarController1.BarItems.Add(this.spreadsheetCommandBarButtonItem3); - this.spreadsheetBarController1.BarItems.Add(this.spreadsheetCommandBarButtonItem4); - this.spreadsheetBarController1.BarItems.Add(this.spreadsheetCommandBarButtonItem5); - this.spreadsheetBarController1.BarItems.Add(this.spreadsheetCommandBarButtonItem6); - this.spreadsheetBarController1.BarItems.Add(this.spreadsheetCommandBarButtonItem7); - this.spreadsheetBarController1.BarItems.Add(this.spreadsheetCommandBarButtonItem8); - this.spreadsheetBarController1.BarItems.Add(this.spreadsheetCommandBarButtonItem9); - // // ModuleEx // this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None; this.BackColor = System.Drawing.SystemColors.Control; this.Controls.Add(this.scc_container); - this.Controls.Add(this.barDockControlLeft); - this.Controls.Add(this.barDockControlRight); - this.Controls.Add(this.barDockControlBottom); - this.Controls.Add(this.barDockControlTop); this.Name = "ModuleEx"; this.Size = new System.Drawing.Size(915, 610); ((System.ComponentModel.ISupportInitialize)(this.scc_container)).EndInit(); @@ -378,10 +209,7 @@ ((System.ComponentModel.ISupportInitialize)(this.pl_right)).EndInit(); this.pl_right.ResumeLayout(false); ((System.ComponentModel.ISupportInitialize)(this.MainBodyTab)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.barManager1)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.spreadsheetBarController1)).EndInit(); this.ResumeLayout(false); - this.PerformLayout(); } @@ -389,22 +217,6 @@ private DevExpress.XtraEditors.SplitContainerControl scc_container; private DevExpress.XtraEditors.PanelControl pl_right; - private DevExpress.XtraBars.BarManager barManager1; - private DevExpress.XtraBars.BarDockControl barDockControlTop; - private DevExpress.XtraBars.BarDockControl barDockControlBottom; - private DevExpress.XtraBars.BarDockControl barDockControlLeft; - private DevExpress.XtraBars.BarDockControl barDockControlRight; - private DevExpress.XtraSpreadsheet.UI.CommonBar commonBar1; - private DevExpress.XtraSpreadsheet.UI.SpreadsheetCommandBarButtonItem spreadsheetCommandBarButtonItem1; - private DevExpress.XtraSpreadsheet.UI.SpreadsheetCommandBarButtonItem spreadsheetCommandBarButtonItem2; - private DevExpress.XtraSpreadsheet.UI.SpreadsheetCommandBarButtonItem spreadsheetCommandBarButtonItem3; - private DevExpress.XtraSpreadsheet.UI.SpreadsheetCommandBarButtonItem spreadsheetCommandBarButtonItem4; - private DevExpress.XtraSpreadsheet.UI.SpreadsheetCommandBarButtonItem spreadsheetCommandBarButtonItem5; - private DevExpress.XtraSpreadsheet.UI.SpreadsheetCommandBarButtonItem spreadsheetCommandBarButtonItem6; - private DevExpress.XtraSpreadsheet.UI.SpreadsheetCommandBarButtonItem spreadsheetCommandBarButtonItem7; - private DevExpress.XtraSpreadsheet.UI.SpreadsheetCommandBarButtonItem spreadsheetCommandBarButtonItem8; - private DevExpress.XtraSpreadsheet.UI.SpreadsheetCommandBarButtonItem spreadsheetCommandBarButtonItem9; - private DevExpress.XtraSpreadsheet.UI.SpreadsheetBarController spreadsheetBarController1; private DevExpress.XtraEditors.PanelControl pl_left; private System.Windows.Forms.Panel pl_left_main; private DevExpress.XtraEditors.PanelControl pl_gridandtree_container; diff --git a/插件库/Lskj.Control/ModuleEx.cs b/插件库/Lskj.Control/ModuleEx.cs index cc64641..4b273f8 100644 --- a/插件库/Lskj.Control/ModuleEx.cs +++ b/插件库/Lskj.Control/ModuleEx.cs @@ -152,6 +152,34 @@ namespace Lskj.Control InitializeComponent(); } + /// + /// Excel 控件包含 SpreadsheetControl、BarManager 和命令注册项, + /// 普通表格模块不应在设计器初始化阶段创建这些重型资源。 + /// + private ExcelControlEx EnsureExcelControl() + { + if (this.excelControlEx1 != null && !this.excelControlEx1.IsDisposed) + { + return this.excelControlEx1; + } + + this.excelControlEx1 = new ExcelControlEx + { + AddEnabled = true, + DeleteEnabled = true, + Dock = DockStyle.Fill, + Margin = new Padding(6), + Name = "excelControlEx1", + PrintEnabled = true, + SaveEnabled = true, + TabIndex = 1, + Visible = false + }; + this.pl_right.Controls.Add(this.excelControlEx1); + this.ExcelControlObj = this.excelControlEx1; + return this.excelControlEx1; + } + /// /// 说明:创建界面 /// 创建人:龚宇超 @@ -284,20 +312,22 @@ namespace Lskj.Control } if (this.IsExcel) { - //由于创建对象时候要注册,所以动态构造这控件不在设计器进行否则表格模式也会弹出注册 + // 只有 Excel 模式才创建 Spreadsheet/Bar 相关资源。 + ExcelControlEx excelControl = EnsureExcelControl(); this.ModuleGridDetailObj.Visible = false; this.repModelDetailEx.Visible = false; - this.excelControlEx1.Visible = true; + excelControl.Visible = true; + excelControl.BringToFront(); if (!Model.DataCaches.GetValue(this, "BasePrimaryKey", out SysModel.ParmaryKey)) { SysModel.ParmaryKey = BaseImpl.GetBasePrimaryKey(this.Model.ModuleCode); } - this.excelControlEx1.AddEnabled = this.SysModel.AddEnable; - this.excelControlEx1.DeleteEnabled = this.SysModel.DeleteEnable; - this.excelControlEx1.PrintEnabled = !string.IsNullOrWhiteSpace(this.SysModel.PrintFile); - this.excelControlEx1.SaveEnabled = this.SysModel.ModifyEnable; - this.excelControlEx1.CreateFile(); - this.excelControlEx1.SaveCallBack += new EventHandler(OnExcelSaveClick); + excelControl.AddEnabled = this.SysModel.AddEnable; + excelControl.DeleteEnabled = this.SysModel.DeleteEnable; + excelControl.PrintEnabled = !string.IsNullOrWhiteSpace(this.SysModel.PrintFile); + excelControl.SaveEnabled = this.SysModel.ModifyEnable; + excelControl.CreateFile(); + excelControl.SaveCallBack += new EventHandler(OnExcelSaveClick); if (!Model.DataCaches.GetValue(this, "BaseGridColumns", out DataTable dtGridColumns)) { dtGridColumns = BaseModuleImpl.GetBaseGridColumns(this.Model.ModuleCode); @@ -314,8 +344,10 @@ namespace Lskj.Control } else { - - this.excelControlEx1.Visible = false; + if (this.excelControlEx1 != null) + { + this.excelControlEx1.Visible = false; + } if (SysModel.isReplacMainDetail == "1") { this.ModuleGridDetailObj.Visible = false; diff --git a/插件库/Lskj.Control/ModuleGridEx.Designer.cs b/插件库/Lskj.Control/ModuleGridEx.Designer.cs index 18c9c50..6a4000b 100644 --- a/插件库/Lskj.Control/ModuleGridEx.Designer.cs +++ b/插件库/Lskj.Control/ModuleGridEx.Designer.cs @@ -13,9 +13,14 @@ /// 如果应释放托管资源,为 true;否则为 false。 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); } diff --git a/插件库/Lskj.Control/SiftColControl/FrmGridSiftProjectManager.cs b/插件库/Lskj.Control/SiftColControl/FrmGridSiftProjectManager.cs index 25c7e09..23c456b 100644 --- a/插件库/Lskj.Control/SiftColControl/FrmGridSiftProjectManager.cs +++ b/插件库/Lskj.Control/SiftColControl/FrmGridSiftProjectManager.cs @@ -111,15 +111,17 @@ namespace Lskj.Control.SiftColControl /// static int CalcIndicatorBestWidth(DevExpress.XtraGrid.Views.Grid.GridView view) { - Graphics graphics = new System.Windows.Forms.Control().CreateGraphics(); - SizeF sizeF = new SizeF(); int count = view.TopRowIndex + ((DevExpress.XtraGrid.Views.Grid.ViewInfo.GridViewInfo)view.GetViewInfo()).RowsInfo.Count; if (count == 0) { count = 30; } - sizeF = graphics.MeasureString(count.ToString(), view.Appearance.Row.Font); - return Convert.ToInt32(sizeF.Width) + 20; + int textWidth = TextRenderer.MeasureText( + count.ToString(), + view.Appearance.Row.Font, + Size.Empty, + TextFormatFlags.NoPadding | TextFormatFlags.SingleLine).Width; + return textWidth + 20; } /// /// 计算默认的宽度 @@ -129,16 +131,18 @@ namespace Lskj.Control.SiftColControl static int CalcIndicatorDefaultWidth(DevExpress.XtraGrid.Views.Grid.GridView view) { var grid = view.GridControl; - Graphics graphics = new System.Windows.Forms.Control().CreateGraphics(); - SizeF sizeF = new SizeF(); int rowHeight = 22;//22是Row的估计高度 if (view.RowHeight > 0) { rowHeight = view.RowHeight; } int count = grid != null ? grid.Height / rowHeight : 30; - sizeF = graphics.MeasureString(count.ToString(), view.Appearance.Row.Font); - return Convert.ToInt32(sizeF.Width) + 20; + int textWidth = TextRenderer.MeasureText( + count.ToString(), + view.Appearance.Row.Font, + Size.Empty, + TextFormatFlags.NoPadding | TextFormatFlags.SingleLine).Width; + return textWidth + 20; } #endregion } diff --git a/插件库/Lskj.Control/SignControlEx.cs b/插件库/Lskj.Control/SignControlEx.cs index 33d1a20..3ad2dab 100644 --- a/插件库/Lskj.Control/SignControlEx.cs +++ b/插件库/Lskj.Control/SignControlEx.cs @@ -211,7 +211,10 @@ namespace Lskj.Control private void btnClear_Click(object sender, EventArgs e) { try { - pictureEdit1.CreateGraphics().Clear(Color.White); + using (Graphics graphics = pictureEdit1.CreateGraphics()) + { + graphics.Clear(Color.White); + } _mousePath.Reset(); } catch (Exception ex) diff --git a/插件库/Lskj.Main/Model/Manager.cs b/插件库/Lskj.Main/Model/Manager.cs index 8d038f3..332cbca 100644 --- a/插件库/Lskj.Main/Model/Manager.cs +++ b/插件库/Lskj.Main/Model/Manager.cs @@ -63,6 +63,9 @@ namespace Lskj.Main.Model private static CancellationTokenSource _sessionMonitorCancellation; private static readonly List SessionMonitorThreads = new List(); + private static readonly object OpeningModuleSync = new object(); + private static readonly HashSet OpeningModuleKeys = + new HashSet(StringComparer.OrdinalIgnoreCase); /// /// 默认下载地址 /// @@ -285,6 +288,8 @@ namespace Lskj.Main.Model /// Params">The URL parameters. public static void OpenModule(string menuId, string menuName, string dllName, string modelFlag, string urlParams) { + string openingModuleKey = null; + bool ownsOpeningGate = false; try { // 验证参数 @@ -293,6 +298,14 @@ namespace Lskj.Main.Model MessageUtil.Show(ResourceKeys.NotFoundMenu); return; } + openingModuleKey = BuildOpeningModuleKey(menuId, dllName, modelFlag); + ownsOpeningGate = TryBeginOpenModule(openingModuleKey); + if (!ownsOpeningGate) + { + // 列数据源初始化期间可能会处理 WinForms 消息。 + // 快速重复点击必须在页签注册前就被拦截,否则会构建多份重型控件树。 + return; + } // 验证权限 int purview = MainImpl.GetUserPurviewsByMenuId(menuId); if (purview == 0) @@ -416,8 +429,52 @@ namespace Lskj.Main.Model string Message = ErrorMessage.PromptErrorMessage(ex); MessageUtil.Show(Message, ex.Message); } + finally + { + if (ownsOpeningGate) + { + EndOpenModule(openingModuleKey); + } + } } + + private static string BuildOpeningModuleKey( + string menuId, + string dllName, + string modelFlag) + { + return string.Join( + "|", + new[] + { + (menuId ?? string.Empty).Trim(), + (dllName ?? string.Empty).Trim(), + (modelFlag ?? string.Empty).Trim() + }); + } + + private static bool TryBeginOpenModule(string openingModuleKey) + { + lock (OpeningModuleSync) + { + if (OpeningModuleKeys.Contains(openingModuleKey)) + { + return false; + } + + OpeningModuleKeys.Add(openingModuleKey); + return true; + } + } + + private static void EndOpenModule(string openingModuleKey) + { + lock (OpeningModuleSync) + { + OpeningModuleKeys.Remove(openingModuleKey); + } + } /// /// 说明:添加模块到tab中 /// 创建人:龚宇超 @@ -432,6 +489,10 @@ namespace Lskj.Main.Model /// The arguments. public static void AddModuleToTab(DllModule module, string[] args) { + string guid = null; + XtraTabPage tp = null; + Form form = null; + bool trackDogVerifiedModule = false; try { bool isQuickLoad = (args[5] + "").Equals(SystemInfo.Instance.QuickMenuId); @@ -441,8 +502,6 @@ namespace Lskj.Main.Model // //QuickMenuForm.BringToFront(); // return; //} - string guid = Guid.NewGuid().ToString(); - XtraTabPage tp = new XtraTabPage(); if (SystemInfo.Instance.IsDogVerify) { if (!CheckPrivateTable()) @@ -497,7 +556,7 @@ namespace Lskj.Main.Model } else { - StaticControl.DogVerifyModuleForms.Add(tp); + trackDogVerifiedModule = true; } } else @@ -532,12 +591,19 @@ namespace Lskj.Main.Model return; } + guid = Guid.NewGuid().ToString(); + tp = new XtraTabPage(); + if (trackDogVerifiedModule) + { + StaticControl.DogVerifyModuleForms.Add(tp); + } + ERPInfo.Instance.selectFormModleId = module.Id; IForm iform = FormHelper.LoadDllForm(module.DllName, args); // 菜单打开的模块默认最大化,界面FormState设置为Normal模式,否则会出现界面不是全屏,会显示默认阴影界面 //iform.SubForm.WindowState = _frmMain.WindowState; iform.SubForm.WindowState = FormWindowState.Normal; ; - Form form = iform.SubForm; // 表示组成应用程序的用户界面的窗口或对话框。 + form = iform.SubForm; // 表示组成应用程序的用户界面的窗口或对话框。 form.Tag = guid; // 这个必须有不然会提示:"不能向tabControl中添加顶级控件" form.TopLevel = isQuickLoad; @@ -599,6 +665,7 @@ namespace Lskj.Main.Model } catch (Exception ex) { + CleanupFailedModuleOpen(guid, tp, form); string Message = ErrorMessage.PromptErrorMessage(ex); MessageUtil.Show(ex.InnerException != null ? ex.InnerException.Message : ex.Message); LogHelper.Instance.WriteError(ex); @@ -606,6 +673,44 @@ namespace Lskj.Main.Model } } + private static void CleanupFailedModuleOpen( + string guid, + XtraTabPage tabPage, + Form form) + { + try + { + if (!string.IsNullOrWhiteSpace(guid)) + { + ModuleForms.Remove(guid); + } + + if (tabPage != null) + { + StaticControl.DogVerifyModuleForms.Remove(tabPage); + if (TabMain != null && TabMain.TabPages.Contains(tabPage)) + { + TabMain.TabPages.Remove(tabPage); + } + } + + if (form != null && !form.IsDisposed) + { + form.Close(); + form.Dispose(); + } + + if (tabPage != null && !tabPage.IsDisposed) + { + tabPage.Dispose(); + } + } + catch (Exception cleanupException) + { + LogHelper.Instance.WriteError(cleanupException); + } + } + /// /// 快速菜单关闭时,清除记录 /// diff --git a/插件库/Lskj.PubModuleDetail/FrmMain.cs b/插件库/Lskj.PubModuleDetail/FrmMain.cs index 03cf3db..c143e01 100644 --- a/插件库/Lskj.PubModuleDetail/FrmMain.cs +++ b/插件库/Lskj.PubModuleDetail/FrmMain.cs @@ -206,7 +206,61 @@ namespace Lskj.PubModuleDetail /// private void OnFrmMainDisposed(object sender, EventArgs e) { - Model.DataCaches.Clear(); + this.FormClosing -= OnClose; + this.Disposed -= OnFrmMainDisposed; + + Dictionary dataCaches = + Model != null ? Model.DataCaches : null; + if (dataCaches == null) + { + return; + } + + DisposeCompletedCacheTasks(dataCaches); + dataCaches.Clear(); + } + + /// + /// 释放模块预加载缓存中已完成任务的等待句柄。 + /// Task.Result 在等待时可能创建底层等待对象,仅清空字典 + /// 不会立即释放这些句柄。 + /// + private static void DisposeCompletedCacheTasks( + Dictionary dataCaches) + { + HashSet tasks = new HashSet(); + foreach (Hashtable cache in dataCaches.Values) + { + if (cache == null) + { + continue; + } + + foreach (object value in cache.Values) + { + Task task = value as Task; + if (task != null) + { + tasks.Add(task); + } + } + } + + foreach (Task task in tasks) + { + if (!task.IsCompleted) + { + continue; + } + + try + { + task.Dispose(); + } + catch (ObjectDisposedException) + { + } + } } } -} \ No newline at end of file +}