/******************************
* 说明:TabControlEx多标签(标签内容包含表格和图表) 应用于审核附加信息、基础档案审核附加信息
* 创建人:龚宇超
* 创建日期:2018-01-10
* 修改人:
* 修改日期:
* 修改备注:
* 版本:1.0.0.0
******************************/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using DevExpress.XtraTab;
using Lskj.Util;
using Lskj.Business.Impl;
using Lskj.Control.Model;
using Lskj.Model;
using DevExpress.XtraEditors;
using Lskj.Data;
using DevExpress.XtraGrid.Columns;
using Lskj.Business;
using DevExpress.XtraGrid.Views.Grid;
using System.Threading.Tasks;
using System.Collections;
using DevExpress.XtraGrid.Views.BandedGrid;
namespace Lskj.Control
{
///
/// 多标签,标签内容包含表格和图表
///
public partial class TabControlEx : UserControl
{
///
/// 是否加载明细刷新
///
/// true if [_ un refresh]; otherwise, false.
private bool _UnRefresh
{
get
{
return Model is DynamicModuleDetailModel || Model is DynamicModuleModel || Model is DynamicProductionModel;
}
}
///
/// 拖拽模式
///
public bool IsDragDetail;
///
/// 拖拽目标主键字段
///
public string DrgaParentPrimaryKey;
///
/// 添加数据sql赋值
///
public string ControlSql;
///
/// tab标签
///
private List _gridDetail;
///
/// tab标签里明细数据
///
private List _gridIntoDetail;
///
/// 是否为Mrp明细页签
///
private bool isMrpDetail = false;
///
/// The system model
///
public DynamicModel Model;
///
/// 父表格
///
public GridControlEx ParentGridEx;
///
/// Mrp父表格
///
public GridControlEx MrpParentGridEx;
///
/// Mrp父明细表格
///
public GridControlEx MrpDetailGridEx;
///
/// 父容器
///
public MyControl ParentControlEx;
///
/// 明细数据里的主表格
///
public ModuleGridEx ModuleGridObj;
///
/// 选项卡
///
public XtraTabControl TabControlObj
{
get { return this.xtc_container; }
}
///
/// 替换其他页签中条件的表
///
public GridControlEx ReplaceControlEx;
///
/// 右键菜单执行后调用
///
/// The sender.
public event EventHandler OnRightCallback;
///
/// 在保存网格回调(右键)
///
/// The sender.
public event EventHandler OnDetailRightCallback;
///
/// 在保存网格回调
///
/// The sender.
public event EventHandler OnDetailSaveGridCallBack;
//拖拽模式拖拽完成委托
public delegate void DragCompleteCallbackEventHandler(object sender, GridDragGridArgs e);
//拖拽模式拖拽完成回调
public event DragCompleteCallbackEventHandler OnDragCompleteCallback;
///
/// 拖拽模式DetailView双击点击事件回调
///
public event EventHandler OnDetailViewDoubleClickCallBack;
///
/// mrp拖拽完成后
///
public event EventHandler OnMrpDragCallback;
public event EventHandler OnMrpBtnClickCallback;
///
/// 明细页签与主模块对应关系
///
public Dictionary> DetailTabPagesDic = new Dictionary>();
///
/// 页签控件集合
///
public Dictionary PageControlsDic = new Dictionary();
///
/// 页签名(判断是否有重复的左右结构)
///
public string DetaiName = string.Empty;
public TabControlEx()
{
InitializeComponent();
this.Disposed += OnTabControlExDisposed;
}
#region ▼ 通用工具 ▼
/// 尝试从 XtraTabPage 解析出 GridDetailModel。
private static GridDetailModel ResolveModel(XtraTabPage page)
{
// ① page.Tag 直接就是 GridDetailModel
if (page.Tag is GridDetailModel m) return m;
// ② page.Tag 是装控件,控件.Tag 才是 GridDetailModel
if (page.Tag is System.Windows.Forms.Control c && c.Tag is GridDetailModel m2) return m2;
// ③ page.Controls 里找第一个带 Tag 的控件
foreach (System.Windows.Forms.Control ctl in page.Controls)
if (ctl.Tag is GridDetailModel m3) return m3;
return null;
}
///
/// 将 DataTable 绑定到指定 XtraTabPage(根据 page.Tag 控件类型自动处理)。
///
private static void BindTableToPage(XtraTabPage page, DataTable table, string lastSql = null)
{
switch (page.Tag)
{
/* ① page.Tag 直接就是 GridControlEx -------------------------- */
case GridControlEx gridEx:
gridEx.LastSearchSql = lastSql ?? gridEx.LastSearchSql;
gridEx.SetGridViewDataSource(table);
break;
/* ② page.Tag 是某种 Control,且本身是 GridControlEx ----------- */
case System.Windows.Forms.Control ctl when ctl is GridControlEx g:
g.LastSearchSql = lastSql ?? g.LastSearchSql;
g.SetGridViewDataSource(table);
break;
/* ③ Tag 是面板/其它容器,递归找内部网格 ------------------------ */
case System.Windows.Forms.Control container when FindGridControlEx(container) is GridControlEx g2:
g2.LastSearchSql = lastSql ?? g2.LastSearchSql;
g2.SetGridViewDataSource(table);
break;
/* ④ 图表控件 ---------------------------------------------------- */
case ChartControlEx chartEx:
chartEx.CreateChart(table);
break;
/* ⑤ 其它控件无需绑定 ------------------------------------------- */
default:
break;
}
}
private static GridControlEx FindGridControlEx(System.Windows.Forms.Control root)
{
foreach (System.Windows.Forms.Control child in root.Controls)
{
if (child is GridControlEx gx) // 找到就返回
return gx;
GridControlEx inner = FindGridControlEx(child);
if (inner != null) return inner; // 递归向下
}
return null;
}
#endregion
#region ▼ 新核心方法 ▼
///
/// 统一刷新页签(既可用于旧底部 tcButtom,也可用于新右侧 rightTab)。
///
protected void SetTabPageDataSource(
XtraTabPage tabPage,
GridControlEx leftGrid,
bool isNull = false,
DataRow overrideRow = null)
{
/********* 0. 前置:获得模型对象 & 当前行 *********/
GridDetailModel model = ResolveModel(tabPage);
if (model == null) { BindTableToPage(tabPage, new DataTable()); return; }
// 行:优先 overrideRow,其次主表当前行
DataRow rowItem = overrideRow ?? leftGrid.GetViewFocusedDataRow();
//if (leftGrid.CustomGroupBandEx != null && overrideRow == null)
// rowItem = leftGrid.CustomGroupBandEx.GetViewFocusedDataRow();
if (leftGrid.CustomGroupSelectedRow != null && overrideRow == null)
rowItem = leftGrid.CustomGroupSelectedRow;
/********* 1. 置空逻辑 ***********************************************/
if (isNull || rowItem == null)
{
// 1-A: 左右结构且允许 UnionLeft → 仍可带条件取数
if (model.IsUnionleft && overrideRow != null)
{
string sqlValue = model.IsReadOnly || model.IsChart
? model.DetailSql
: model.SystemModel.MenuSql;
sqlValue = ReplaceHelper.ReplaceRowParam(rowItem, sqlValue);
sqlValue = ReplaceHelper.ReplaceWhereCond(sqlValue);
DataTable dt = MainImpl.GetDataTableResult(sqlValue);
BindTableToPage(tabPage, dt);
}
else
{
BindTableToPage(tabPage, new DataTable());
}
return;
}
/********* 2. PageVisibleCond(可见性判定) ***************************/
if (leftGrid.SysModel!=null && !string.IsNullOrEmpty(leftGrid.SysModel.PageVisbleCond))
{
string condSql = ReplaceHelper.ReplaceRowParam(rowItem,
ReplaceHelper.ReplaceUserInfo(leftGrid.SysModel.PageVisbleCond));
string numberList = MainImpl.GetResult(condSql) + "";
if (!string.IsNullOrEmpty(numberList))
{
string orderIdStr = model.Orderid.ToString();
bool visible = numberList.Split(',').Contains(orderIdStr);
tabPage.PageVisible = visible;
if (!visible) { BindTableToPage(tabPage, new DataTable()); return; }
}
}
/********* 3. 浏览器页签 ************************************************/
if (tabPage.Tag is FrmWebBrowser ||
tabPage.Tag is FrmWebBrowser2 ||
tabPage.Tag is FrmMiniBlink)
{
string url = ReplaceHelper.ReplaceRowParam(rowItem,
ReplaceHelper.ReplaceUserInfo(model.DetailSql));
url = url.StartsWith("http") ? url : SystemInfo.Instance.OAUrl + url;
switch (tabPage.Tag)
{
case FrmWebBrowser w1: w1.LoadUrl(url); break;
case FrmWebBrowser2 w2: w2.LoadUrl(url); break;
case FrmMiniBlink mb: mb.LoadUrl(url); break;
}
return;
}
/********* 4. 多明细 TabMultipledetails ********************************/
if (tabPage.Tag is TabMultipledetails multi)
{
multi.SetConditionValues(rowItem);
// 主格
GridControlEx grdMain = multi.SplitMain.Panel1.Tag as GridControlEx;
GridDetailModel mainM = grdMain.Tag as GridDetailModel;
string sqlMain = GetSearchSql(mainM, rowItem);
DataTable mainTable = MainImpl.GetDataTableResult(sqlMain);
grdMain.LastSearchSql = sqlMain;
grdMain.SetGridViewDataSource(mainTable);
// 附格 / 图表
System.Windows.Forms.Control rightCtl = multi.SplitMain.Panel2.Tag as System.Windows.Forms.Control;
if (rightCtl is GridControlEx grdAdd)
{
GridDetailModel addM = grdAdd.Tag as GridDetailModel;
string sqlAdd = GetSearchSql(addM, rowItem);
if (!mainM.IsUnioDetail)
{
grdAdd.LastSearchSql = sqlAdd;
grdAdd.SetGridViewDataSource(MainImpl.GetDataTableResult(sqlAdd));
}
else if (mainTable.Rows.Count == 0) // 主表无数据 → 清空
{
grdAdd.LastSearchSql = "";
grdAdd.SetGridViewDataSource(new DataTable());
}
}
else if (rightCtl is ChartControlEx chartAdd)
{
GridDetailModel addM = chartAdd.Tag as GridDetailModel;
string sqlAdd = GetSearchSql(addM, rowItem);
chartAdd.CreateChart(MainImpl.GetDataTableResult(sqlAdd));
}
tabPage.Text = $"{mainM.DetailName}({mainTable.Rows.Count}条)";
tabPage.Appearance.Header.ForeColor =
mainTable.Rows.Count > 0 ? Color.Red : Color.Black;
return;
}
/********* 5. 普通 Grid / Chart / 动态列 ******************************/
if (!string.IsNullOrEmpty(model.UnionModule) &&
string.IsNullOrEmpty(model.UnionValue) &&
string.IsNullOrEmpty(model.UnionCond))
return; // 无关联字段→不刷
if (model.IsDrag) return; // 拖拽页签不刷
string finalSql = GetSearchSql(model, rowItem);
//if (model.DynamicDetails && rowItem.Table.Columns.Contains("DisplayColumns"))
// tabContainer.SetGridDisplayColumns?.Invoke(tabPage, rowItem["DisplayColumns"] + "");
DataTable table = MainImpl.GetDataTableResult(finalSql);
BindTableToPage(tabPage, table, finalSql);
tabPage.Text = $"{model.DetailName}({table.Rows.Count}条)";
tabPage.Appearance.Header.ForeColor = table.Rows.Count > 0 ? Color.Red : Color.FromArgb(0, 0, 0);
// 首次加载自动查询
if (model.SystemModel != null && model.SystemModel.isFirstLoad == 1
&& tabPage.Tag is GridControlEx gc)
{
gc.ParentControl.SearchGrid();
tabPage.Text = $"{model.DetailName}({gc.ParentControl.GridRowCount}条)";
tabPage.Appearance.Header.ForeColor = gc.ParentControl.GridRowCount > 0 ? Color.Red : Color.FromArgb(0, 0, 0);
}
// 行定位 / 按钮状态
if (tabPage.Controls.OfType().FirstOrDefault() is ModuleGridEx mod)
{
mod.ParentButtonState(rowItem);
mod.SelectTheSpecifiedRow();
}
}
#endregion
/// 根据左侧选中行刷新右侧整个 TabControl。
private void RefreshRightTab(XtraTabControl rightTab, GridControlEx leftGrid)
{
DataRow rowItem = leftGrid.GetViewFocusedDataRow();
foreach (XtraTabPage page in rightTab.TabPages)
{
bool isNull = rowItem == null;
SetTabPageDataSource(page, leftGrid, isNull, rowItem);
}
}
///
/// 新模式加载明细控件
///
///
///
///
public void InitTabPages(List gridDetail, bool isGridmerge = true, bool isAddPages = false)
{
if (ParentGridEx != null && ParentGridEx.CustomGroupBandEx != null)
{
ParentGridEx.CustomGroupBandEx.BandedView.LeftCoordChanged += OnBandedViewLeftCoordChanged;
ParentGridEx.CustomGroupBandEx.BandedView.ColumnWidthChanged += OnBandedViewColumnWidthChanged;
ParentGridEx.OnBuildGroupedColumnCallBack += OnBandedViewColumnWidthChanged;
}
if (ParentGridEx != null && ParentGridEx.CustomGroupTreeBandEx != null)
{
ParentGridEx.CustomGroupTreeBandEx.TreeListObj.LeftCoordChanged += OnBandedViewLeftCoordChanged; ;
ParentGridEx.CustomGroupTreeBandEx.TreeListObj.ColumnWidthChanged += OnBandedViewColumnWidthChanged;
ParentGridEx.OnBuildGroupedColumnCallBack += OnBandedViewColumnWidthChanged;
}
this._gridDetail = gridDetail;
if (!isAddPages) this.xtc_container.TabPages.Clear();
// 1️⃣ 预分组:Rightdockid > 0 的明细
var rightGroups = gridDetail
.Where(m => m.Rightdockid > 0)
.GroupBy(m => m.Rightdockid)
.ToDictionary(g => g.Key, g => g.ToList());
Dictionary