fix(legacy): keep bill cache control creation on UI thread

This commit is contained in:
2026-08-30 21:42:56 +08:00
parent 769aa52241
commit 0058939a8a
4 changed files with 322 additions and 277 deletions
+109 -112
View File
@@ -40,6 +40,24 @@ namespace Lskj.PubBillManagement
{
public partial class BillModule : UserControl
{
private static void AttachCachedTask<T>(
Dictionary<object, Hashtable> cachesDic,
object cacheOwner,
string cacheKey,
object control,
string controlKey)
{
if (cachesDic == null || cacheOwner == null || control == null ||
cachesDic.GetTask<T>(control, controlKey) != null)
{
return;
}
Task<T> task = cachesDic.GetTask<T>(cacheOwner, cacheKey);
if (task != null)
cachesDic.AddTask(control, controlKey, task);
}
/// <summary>
/// 是否为初始化创建
/// </summary>
@@ -418,12 +436,13 @@ namespace Lskj.PubBillManagement
}));
cachesDic.AddTask(tb_buttom, "DynamicModel", dynamicModelTask);
cachesDic.AddTask(tb_buttom, "Details", detailTask);
tb_buttom.GetDataCaches(cachesDic);
// TabControlEx.GetDataCaches 会创建 Grid、ModuleGrid、浏览器等
// WinForms/DevExpress 控件,延后到 InitializeBillSource
// 在 UI 线程执行。
Task<bool> initSourcesTask = cachesDic.AddTask(this, "InitSourcesTask", new Task<bool>(() =>
{
Hashtable htTable = sourcesTask.Result;
DataTable masterTable = htTable["master"] as DataTable;
DataTable detailTable = htTable["detail"] as DataTable;
for (int i = 0; i < masterTable.Rows.Count; i++)
{
DataRow sourceModelRow = masterTable.Rows[i];
@@ -434,137 +453,75 @@ namespace Lskj.PubBillManagement
{
return BaseModuleImpl.GetCustomQueryFields(model.FormKey);
}));
#region
GridControlEx gridControl = null;
TreeViewEx treeView = null;
// 后台阶段只加载数据,不构造任何 WinForms/DevExpress
// 对象。缓存以 BillModuleModel 为所有者,UI 创建实际
// 控件后再绑定需要的任务。
if (model.SourceType == 1)
{
// 来源为树类型
treeView = new TreeViewEx();
billModuleModel.SourceControl = treeView;
Task<DataTable> bindTreeTableTask = cachesDic.AddTask(treeView, "BindTreeTable", new Task<DataTable>(() =>
cachesDic.AddTask(billModuleModel, "BindTreeTable", new Task<DataTable>(() =>
{
return BaseImpl.GetDataTableResult(model.SourceSql);
}));
}
else if (model.SourceType == 5)
{
model.ChangeSourceType(2);//单据来源显示条数
}
else if (model.SourceType == 3 || model.SourceType == 4)
{
gridControl = new TreeGridControlEx();
billModuleModel.SourceControl = gridControl;
Task<DataTable> sourceColumnsTask = cachesDic.AddTask(gridControl, "SourceColumns", new Task<DataTable>(() =>
{
return BillImpl.GetSourceColumns(model.Id);
}));
Task<DataTable> sourceGridRowColorsTask = cachesDic.AddTask(gridControl, "BaseGridRowColors", new Task<DataTable>(() =>
{
return BaseModuleImpl.GetBaseGridRowColors("BILLSOURCE_" + model.FormKey);
}));
Task<DataTable> sourceGridRightMenusTask = cachesDic.AddTask(gridControl, "BaseGridRightMenus", new Task<DataTable>(() =>
{
return BaseModuleImpl.GetBaseGridRightMenus("BILLSOURCE_" + model.FormKey);
}));
}
else
{
// 来源为表格类型
gridControl = new GridControlEx();
billModuleModel.SourceControl = gridControl;
Task<DataTable> sourceColumnsTask = cachesDic.AddTask(gridControl, "SourceColumns", new Task<DataTable>(() =>
if (model.SourceType == 5)
model.ChangeSourceType(2);//单据来源显示条数
cachesDic.AddTask(billModuleModel, "SourceColumns", new Task<DataTable>(() =>
{
return BillImpl.GetSourceColumns(model.Id);
}));
//创建表格列
cachesDic.AddTask(gridControl, "DynamicModel", dynamicModelTask);
gridControl.GetDataCaches(cachesDic, GridCustomColumnStruct.BillSourceGridView + model.FormKey);
Task<DataTable> sourceGridRowColorsTask = cachesDic.AddTask(gridControl, "BaseGridRowColors", new Task<DataTable>(() =>
cachesDic.AddTask(billModuleModel, "SourceCustomColumnByDatabase", new Task<DataTable>(() =>
{
return GridExtend.GetCustomColumnByDatabase(
GridCustomColumnStruct.BillSourceGridView + model.FormKey);
}));
cachesDic.AddTask(billModuleModel, "SourceBaseGridRowColors", new Task<DataTable>(() =>
{
return BaseModuleImpl.GetBaseGridRowColors("BILLSOURCE_" + model.FormKey);
}));
Task<DataTable> sourceGridRightMenusTask = cachesDic.AddTask(gridControl, "BaseGridRightMenus", new Task<DataTable>(() =>
cachesDic.AddTask(billModuleModel, "SourceBaseGridRightMenus", new Task<DataTable>(() =>
{
return BaseModuleImpl.GetBaseGridRightMenus("BILLSOURCE_" + model.FormKey);
}));
}
#endregion
#region
GridControlEx gridDetail = new GridControlEx();
if (model.sourceDetailType.Equals("1"))
if (string.IsNullOrWhiteSpace(model.DetailMenuCode))
{
//明细为树表格
gridDetail = new TreeGridControlEx();
billModuleModel.SourceDetailControl = gridDetail;
//创建表格列
cachesDic.AddTask(gridDetail, "DynamicModel", dynamicModelTask);
gridDetail.GetDataCaches(cachesDic, GridCustomColumnStruct.BillSourceDetailGridView + model.FormKey);
Task<DataTable> detailGridRowColorsTask = cachesDic.AddTask(gridDetail, "BaseGridRowColors", new Task<DataTable>(() =>
cachesDic.AddTask(billModuleModel, "SourceDetailCustomColumnByDatabase", new Task<DataTable>(() =>
{
return GridExtend.GetCustomColumnByDatabase(
GridCustomColumnStruct.BillSourceDetailGridView + model.FormKey);
}));
cachesDic.AddTask(billModuleModel, "SourceDetailBaseGridRowColors", new Task<DataTable>(() =>
{
return BaseModuleImpl.GetBaseGridRowColors("SOURCEDETAIL_" + model.FormKey);
}));
Task<DataTable> detailGridRightMenusTask = cachesDic.AddTask(gridDetail, "BaseGridRightMenus", new Task<DataTable>(() =>
cachesDic.AddTask(billModuleModel, "SourceDetailBaseGridRightMenus", new Task<DataTable>(() =>
{
return BaseModuleImpl.GetBaseGridRightMenus("BILLSOURCEDT_" + model.FormKey);
}));
}
else
{
gridDetail = new GridControlEx();
billModuleModel.SourceDetailControl = gridDetail;
//创建表格列
cachesDic.AddTask(gridDetail, "DynamicModel", dynamicModelTask);
gridDetail.GetDataCaches(cachesDic, GridCustomColumnStruct.BillSourceDetailGridView + model.FormKey);
Task<DataTable> detailGridRowColorsTask = cachesDic.AddTask(gridDetail, "BaseGridRowColors", new Task<DataTable>(() =>
{
return BaseModuleImpl.GetBaseGridRowColors("SOURCEDETAIL_" + model.FormKey);
}));
Task<DataTable> detailGridRightMenusTask = cachesDic.AddTask(gridDetail, "BaseGridRightMenus", new Task<DataTable>(() =>
{
return BaseModuleImpl.GetBaseGridRightMenus("BILLSOURCEDT_" + model.FormKey);
}));
//明细的明细(明细分成左右2个)
if (!string.IsNullOrEmpty(model.SourceDetailsDetailsSql))
{
GridControlEx gridDetail_Details = new GridControlEx();
billModuleModel.SourceDetailDetailControl = gridDetail_Details;
//创建只读列
Task<DataTable> detailDetailsTask = cachesDic.AddTask(gridDetail_Details, "DetailDetails", new Task<DataTable>(() =>
cachesDic.AddTask(billModuleModel, "DetailDetails", new Task<DataTable>(() =>
{
return BaseModuleImpl.getDetail_Details(model.FormKey);
}));
//创建表格列
cachesDic.AddTask(gridDetail_Details, "DynamicModel", dynamicModelTask);
gridDetail_Details.GetDataCaches(cachesDic);
Task<DataTable> detailDetailsGridRightMenusTask = cachesDic.AddTask(gridDetail_Details, "BaseGridRightMenus", new Task<DataTable>(() =>
cachesDic.AddTask(billModuleModel, "SourceDetailDetailsCustomColumnByDatabase", new Task<DataTable>(() =>
{
return GridExtend.GetCustomColumnByDatabase(string.Empty);
}));
cachesDic.AddTask(billModuleModel, "SourceDetailDetailsBaseGridRightMenus", new Task<DataTable>(() =>
{
return BaseModuleImpl.GetBaseGridRightMenus("BILLSOURCEDTX_" + model.FormKey);
}));
}
}
#endregion
BillModuleModelDic.Add(sourceModelRow, billModuleModel);
#region
Task<MyControl> searchControlTask = cachesDic.AddTask(sourceModelRow, "SearchControl", new Task<MyControl>(() =>
{
DataTable controls = customQueryFieldsTask.Result;
MyControl searchControl = null;
if (model.SourceType != 1 || (controls != null && controls.Rows.Count > 0))
{
// 创建自定义条件
string searchSql = model.SourceType == 1 ? Regex.Replace(model.DetailSql, "{speciesno}", "", RegexOptions.IgnoreCase) : model.SourceSql;
searchControl = new MyControl(searchSql, gridControl == null ? gridDetail : gridControl, treeView);
searchControl.Model = dynamicModel;
searchControl.OtherParams = dynamicModel.OtherParams();
cachesDic.AddTask(searchControl, "DynamicModel", dynamicModelTask);
cachesDic.AddTask(searchControl, "ControlsTable", customQueryFieldsTask);
searchControl.GetSearchDataCaches(cachesDic);
}
return searchControl;
}));
#endregion
}
return true;
}));
@@ -713,6 +670,13 @@ namespace Lskj.PubBillManagement
this.xtc_main_container.TabPages.Clear();
Dictionary<object, Hashtable> dataCaches = SysModel != null ? SysModel.DataCaches : null;
if (dataCaches != null &&
dataCaches.GetTask<DynamicModel>(tb_buttom, "DynamicModel") != null &&
dataCaches.GetTask<List<GridDetailModel>>(tb_buttom, "Details") != null)
{
// 该方法会预创建附加页控件,必须在 UI 线程执行。
tb_buttom.GetDataCaches(dataCaches);
}
if (!dataCaches.GetValue(this, "Details", out List<GridDetailModel> attachModels))
{
attachModels = GetAttachTabs();
@@ -790,7 +754,7 @@ namespace Lskj.PubBillManagement
treeView.Dock = DockStyle.Fill;
treeView.TreeNodeKeyField = model.SourceKeyField;
treeView.TreeNodeTextField = model.SourceResult;
if (!dataCaches.GetValue(treeView, "BindTreeTable", out DataTable bindTreeTable))
if (!dataCaches.GetValue(billModuleModel, "BindTreeTable", out DataTable bindTreeTable))
{
bindTreeTable = BaseImpl.GetDataTableResult(model.SourceSql);
}
@@ -814,15 +778,18 @@ namespace Lskj.PubBillManagement
gridControl.BorderStyle = System.Windows.Forms.BorderStyle.None;
gridControl.Model = this.SysModel;
if (!dataCaches.GetValue(gridControl, "SourceColumns", out DataTable dtSourceColumns))
AttachCachedTask<DataTable>(dataCaches, billModuleModel,
"SourceCustomColumnByDatabase", gridControl,
"CustomColumnByDatabase");
if (!dataCaches.GetValue(billModuleModel, "SourceColumns", out DataTable dtSourceColumns))
{
dtSourceColumns = BillImpl.GetSourceColumns(model.Id);
}
if (!dataCaches.GetValue(gridControl, "BaseGridRowColors", out DataTable dtBaseGridRowColors))
if (!dataCaches.GetValue(billModuleModel, "SourceBaseGridRowColors", out DataTable dtBaseGridRowColors))
{
dtBaseGridRowColors = BaseModuleImpl.GetBaseGridRowColors("BILLSOURCE_" + model.FormKey);
}
if (!dataCaches.GetValue(gridControl, "BaseGridRightMenus", out DataTable dtBaseGridRightMenus))
if (!dataCaches.GetValue(billModuleModel, "SourceBaseGridRightMenus", out DataTable dtBaseGridRightMenus))
{
dtBaseGridRightMenus = BaseModuleImpl.GetBaseGridRightMenus("BILLSOURCE_" + model.FormKey);
}
@@ -855,19 +822,22 @@ namespace Lskj.PubBillManagement
gridControl.Dock = DockStyle.Fill;
gridControl.ExportPermission = this.BillModel.ExportPermission;
AttachCachedTask<DataTable>(dataCaches, billModuleModel,
"SourceCustomColumnByDatabase", gridControl,
"CustomColumnByDatabase");
if (model.LoadFilter)
{
gridControl.GridView.OptionsView.ShowAutoFilterRow = true;
}
if (!dataCaches.GetValue(gridControl, "SourceColumns", out DataTable dtSourceColumns))
if (!dataCaches.GetValue(billModuleModel, "SourceColumns", out DataTable dtSourceColumns))
{
dtSourceColumns = BillImpl.GetSourceColumns(model.Id);
}
if (!dataCaches.GetValue(gridControl, "BaseGridRowColors", out DataTable dtBaseGridRowColors))
if (!dataCaches.GetValue(billModuleModel, "SourceBaseGridRowColors", out DataTable dtBaseGridRowColors))
{
dtBaseGridRowColors = BaseModuleImpl.GetBaseGridRowColors("BILLSOURCE_" + model.FormKey);
}
if (!dataCaches.GetValue(gridControl, "BaseGridRightMenus", out DataTable dtBaseGridRightMenus))
if (!dataCaches.GetValue(billModuleModel, "SourceBaseGridRightMenus", out DataTable dtBaseGridRightMenus))
{
dtBaseGridRightMenus = BaseModuleImpl.GetBaseGridRightMenus("BILLSOURCE_" + model.FormKey);
}
@@ -979,12 +949,15 @@ namespace Lskj.PubBillManagement
gridDetail = sourceDetailControl != null ? (TreeGridControlEx)sourceDetailControl : new TreeGridControlEx();
gridDetail.Model = this.SysModel;
gridDetail.Dock = DockStyle.Fill;
AttachCachedTask<DataTable>(dataCaches, billModuleModel,
"SourceDetailCustomColumnByDatabase", gridDetail,
"CustomColumnByDatabase");
gridDetail.SetReadOnlyColumns(detailColumns == null || detailColumns.Length == 0 ? new DataTable() : detailColumns.CopyToDataTable(), GridCustomColumnStruct.BillSourceDetailGridView + model.FormKey);
if (!dataCaches.GetValue(gridDetail, "BaseGridRowColors", out DataTable dtBaseGridRowColors))
if (!dataCaches.GetValue(billModuleModel, "SourceDetailBaseGridRowColors", out DataTable dtBaseGridRowColors))
{
dtBaseGridRowColors = BaseModuleImpl.GetBaseGridRowColors("SOURCEDETAIL_" + model.FormKey);
}
if (!dataCaches.GetValue(gridDetail, "BaseGridRightMenus", out DataTable dtBaseGridRightMenus))
if (!dataCaches.GetValue(billModuleModel, "SourceDetailBaseGridRightMenus", out DataTable dtBaseGridRightMenus))
{
dtBaseGridRightMenus = BaseModuleImpl.GetBaseGridRightMenus("BILLSOURCEDT_" + model.FormKey);
}
@@ -1012,17 +985,20 @@ namespace Lskj.PubBillManagement
gridDetail = sourceDetailControl != null ? (GridControlEx)sourceDetailControl : new GridControlEx();
gridDetail.Model = this.SysModel;
gridDetail.Dock = DockStyle.Fill;
AttachCachedTask<DataTable>(dataCaches, billModuleModel,
"SourceDetailCustomColumnByDatabase", gridDetail,
"CustomColumnByDatabase");
gridDetail.SetReadOnlyColumns(detailColumns == null || detailColumns.Length == 0 ? new DataTable() : detailColumns.CopyToDataTable(), GridCustomColumnStruct.BillSourceDetailGridView + model.FormKey);
if (model.DetailedLoadFilter)
{
gridDetail.GridView.OptionsView.ShowAutoFilterRow = true;
}
if (!dataCaches.GetValue(gridDetail, "BaseGridRowColors", out DataTable dtBaseGridRowColors))
if (!dataCaches.GetValue(billModuleModel, "SourceDetailBaseGridRowColors", out DataTable dtBaseGridRowColors))
{
dtBaseGridRowColors = BaseModuleImpl.GetBaseGridRowColors("SOURCEDETAIL_" + model.FormKey);
}
if (!dataCaches.GetValue(gridDetail, "BaseGridRightMenus", out DataTable dtBaseGridRightMenus))
if (!dataCaches.GetValue(billModuleModel, "SourceDetailBaseGridRightMenus", out DataTable dtBaseGridRightMenus))
{
dtBaseGridRightMenus = BaseModuleImpl.GetBaseGridRightMenus("BILLSOURCEDT_" + model.FormKey);
}
@@ -1036,13 +1012,16 @@ namespace Lskj.PubBillManagement
gridDetail_Details.Model = this.SysModel;
gridDetail_Details.Dock = DockStyle.Fill;
//创建只读列
if (!dataCaches.GetValue(gridDetail_Details, "Detail_Details", out DataTable dataTable))
if (!dataCaches.GetValue(billModuleModel, "DetailDetails", out DataTable dataTable))
{
dataTable = BaseModuleImpl.getDetail_Details(model.FormKey);
}
AttachCachedTask<DataTable>(dataCaches, billModuleModel,
"SourceDetailDetailsCustomColumnByDatabase",
gridDetail_Details, "CustomColumnByDatabase");
gridDetail_Details.SetReadOnlyColumns(dataTable);
//设置右键
if (!dataCaches.GetValue(gridDetail_Details, "BaseGridRightMenus", out DataTable dttBaseGridRightMenus))
if (!dataCaches.GetValue(billModuleModel, "SourceDetailDetailsBaseGridRightMenus", out DataTable dttBaseGridRightMenus))
{
dttBaseGridRightMenus = BaseModuleImpl.GetBaseGridRightMenus("BILLSOURCEDTX_" + model.FormKey);
}
@@ -1073,6 +1052,7 @@ namespace Lskj.PubBillManagement
splitContainerControl.Parent = tabDetail;
unionModel.GridDetailDetailControlObj = gridDetail_Details;
billModuleModel.SourceDetailDetailControl = gridDetail_Details;
}
else
{
@@ -1103,6 +1083,11 @@ namespace Lskj.PubBillManagement
#endregion
billModuleModel.SourceControl =
treeView != null ? (object)treeView : gridControl;
billModuleModel.SourceDetailControl = gridDetail;
BillModuleModelDic[sourceModelRow] = billModuleModel;
#region
if (model.SourceType == 1 && (controls == null || controls.Rows.Count == 0))
{
@@ -1123,9 +1108,21 @@ namespace Lskj.PubBillManagement
// 创建自定义条件
string searchSql = model.SourceType == 1 ? Regex.Replace(model.DetailSql, "{speciesno}", "", RegexOptions.IgnoreCase) : model.SourceSql;
PanelControl searchPanel = new PanelControl();
if (!dataCaches.GetValue(sourceModelRow, "SearchControl", out MyControl searchControl))
MyControl searchControl =
new MyControl(searchSql,
gridControl == null ? gridDetail : gridControl,
treeView)
{
searchControl = new MyControl(searchSql, gridControl == null ? gridDetail : gridControl, treeView);
Model = this.SysModel,
OtherParams = this.SysModel.OtherParams()
};
if (dataCaches != null)
{
dataCaches.AddTask(searchControl, "DynamicModel",
new Task<DynamicModel>(() => this.SysModel));
dataCaches.AddTask(searchControl, "ControlsTable",
new Task<DataTable>(() => controls));
searchControl.GetSearchDataCaches(dataCaches);
}
searchControl.OnSearchBeforeCallBack += new SearchEventHandler(OnSearchBefore);
searchControl.OnSearchAfterCallBack += new EventHandler(OnSearchAfterd);
@@ -2471,4 +2468,4 @@ namespace Lskj.PubBillManagement
}
}
}