作为一个ERP数据处理框架,大部分的开发场景都差不多。

理想中,对于通用数据处理,我的步骤如下:

1、为窗体指定数据来源(数据表/查询等);

2、拖入编辑控件,指定绑定字段;

3、结束。

为此,我设计了几个基类窗体,给它们分成几个场景(如无数据/单表数据/主从表/多表关联等),在不同的业务模型下,我选取相应的基类窗体进行继承。

首先,看看最基础的基类窗体,它包含了基础的处理(诸如多语言加载、权限判断、状态刷新、自动数据绑定等基础方法和属性):

    /// <summary>
/// 窗体基类
/// </summary>
public partial class Fm11Base : Form
{
//private:只能在本类中使用
//protected:在本类中及其子类中可以使用
//internal:同一命名空间(程序集)中的类可以使用
//public:所有类均可使用 /// <summary>
/// 用于耗时任务展示任务运行状态
/// </summary>
protected Fm11BgwkStatus fm11BgwkStatus; [Description("窗体除基本状态控制查改删外,是否跳过其它权限控制.为是的情况下,所有权限判定都将为真."), DefaultValue(false), Browsable(true)]
public bool IgnoreRightsControl { get; set; } /// <summary>
/// <para>指定当前绑定的数据源.在获取数据来源后并绑定后记录一个标记值,用于一个窗体多个绑定源时区分当前所绑定的数据源.</para>
/// 单个绑定源可在FormOnload时绑定一次,无需设置
/// </summary>
public BindingSource CurBindingSource { get; set; } /// <summary>
/// <para>指定已经绑定过的数据源名称,避免重复绑定</para>
/// 一般只有一个BSMaster,当存在多个时,以A,B,C方式存入.
/// </summary>
public List<string> HasBindBSNames { get; set; } = new List<string>(); /// <summary>
/// 窗体当前绑定的主要数据源的新增/编辑位置(当记录进入新增和编辑状态时,需写入此值;当浏览到其它记录以便复制粘贴时,可以利用此状态)
/// </summary>
public int CurBSEditPos = -; /// <summary>
/// 窗体当前绑定的主要数据源的当前位置(不一定是编辑位置)
/// </summary>
public int CurBSPosition = ; /// <summary>
/// 窗体正在创建时(不是Loading),利用此标记在加载数据时不触发CurrentChange事件
/// </summary>
public bool OnIniting = false; /// <summary>
/// 编辑状态标记:0-浏览,1-新增,2-编辑
/// </summary>
[Description("编辑状态标记:0-浏览,1-新增,2-编辑"), Browsable(false)]
public int EditStatus; /// <summary>
/// 从对象列表中定义的加载参数,窗体加载时提供.主要用于同一个窗体在不同模块加载时根据此参数进行数据过滤.如果权限窗体,不同模块点开则由只显示指定模块的数据.
/// </summary>
[Description("窗体加载时提供的参数,主要用于同一个窗体在不同模块加载时根据此参数进行数据过滤.如果权限窗体,不同模块点开则由只显示指定模块的数据."), Browsable(true)]
public string OnLoadParams { get; set; } /// <summary>
/// 当前用户打开窗体后带入的权限列表
/// </summary>
[Description("当前用户打开窗体后带入的权限列表"), Browsable(false)]
public string RightsList; /// <summary>
/// 默认将ENTER键动作转为TAB
/// </summary>
public bool EnterToTAB = true; /// <summary>
/// 显示模式:0为帐户ID;1为姓名;2为用户全名; 3为用户名 - 姓名;4为用户名 - 全名;
/// </summary>
protected internal int UserNameDispType = ; /// <summary>
/// 所有窗体的基类,可以设置多语言等通用功能
/// </summary>
public Fm11Base()
{
OnIniting = true;
InitializeComponent();
} /// <summary>
/// 按指定的键值直接定位到某条记录
/// </summary>
/// <param name="tagBS">指定BS,有可能是定位其它数据源而非主数据</param>
/// <param name="tagDT">必须指定DT,与BS匹配,除直接DT外,有可能是Dataset的某一Table或关联表的连接</param>
/// <param name="keyFieldName">字段名称</param>
/// <param name="pKeyValue">字段值</param>
public virtual void GotoRecord(BindingSource tagBS, DataTable tagDT, string keyFieldName, object pKeyValue)
{
if (tagBS == null)
{
MyMsg.Warning("数据源未完成初始化,无法定位.");
return;
}
if (EditStatus != )
{
MyMsg.Warning("窗体正在编辑中,无法定位.");
return;
}
HpDataTable.GotoRecord(tagBS, tagDT, keyFieldName, pKeyValue);
} /// <summary>
/// 设置当前窗体的状态栏标签(名称需指定为:LabStsMain)字符串(不是主框架的状态栏字符);
/// 输入..将默认显示(等待指令...)
/// </summary>
/// <param name="statusText"></param>
protected void SetMainStatus(string statusText)
{
object o = GetObjInstance("LabStsMain");
if (o == null) o = GetObjInstance("StsLabMain");
if (o != null)
{
if (statusText == "..") statusText = MultiLang.Surface(null, "Waitting", "", true);
((ToolStripStatusLabel)o).Text = statusText;
Refresh();
}
else
{
MyMsg.Exclamation("The status label does not exist.");
return;
}
} private void Fm11Base_FormClosing(object sender, FormClosingEventArgs e)
{
if (EditStatus > )
{
if (e.CloseReason == CloseReason.UserClosing || e.CloseReason == CloseReason.FormOwnerClosing || e.CloseReason == CloseReason.None)
{
if (MyMsg.Question("当前窗体正处于"+(EditStatus==?"新增":"编辑")+"状态,确定要继续关闭吗?") == DialogResult.No)
{
e.Cancel = true;
}
}
}
}
/// <summary>
/// 获取当前的活动控件
/// </summary>
/// <returns></returns>
protected Control GetActiveControl()
{
Control activeControl = this.ActiveControl;
while ((activeControl as ContainerControl) != null)
{
activeControl = (activeControl as ContainerControl).ActiveControl;
}
return activeControl;
}
/// <summary>
/// 截获系统消息
/// </summary>
/// <param name="msg"></param>
/// <param name="keyData"></param>
/// <returns></returns>
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
Control actControl = GetActiveControl();
if ((keyData == Keys.Enter) && (EnterToTAB == true) && !(actControl is Button))
{
Type mtype = actControl.GetType();
if (mtype.GetProperty("AcceptsReturn") != null)
{
bool acptRtn =OString.NZ2Bool(mtype.GetProperty("AcceptsReturn").GetValue(actControl, null));
if (!acptRtn)
{
SendKeys.Send("{TAB}");
return true;
}
else
{
return false;
}
}
else
{
SendKeys.Send("{TAB}");
return true;
}
}
else if (keyData == Keys.F12)
{
Control control = GetActiveControl();
if (control == null) return false;
string tipStr = OString.NZ2Str(control.AccessibleDescription).Trim();
if (!string.IsNullOrEmpty(tipStr))
{
if (control.Parent != null)
{
TtipF12.Show(tipStr, control.Parent, control.Location.X, control.Location.Y + , );
return false;
}
else return false;
}
else return false;
}
else
{
return false;
}
} /// <summary>
/// 判断当前用户是否在当前窗体拥有权限(可支持多个权限同时判断,以逗号分割)
/// <para>同时满足时才会返回True</para>
/// </summary>
/// <param name="rightCodes">add,open等权限码,不区分大小写</param>
/// <returns></returns>
protected bool HasRights(string rightCodes)
{
if (IgnoreRightsControl || (GlbInfo.User.IsAdmin)) return true;
if (OString.ListInListNeedAll(rightCodes, RightsList,",",true))
{
return true;
}
else return false;
} /// <summary>
/// 判断当前用户是否在指定的业务角色中(可支持多个角色同时判断,以逗号分割)
/// <para>同时满足时才会返回True</para>
/// </summary>
/// <param name="roleRKEYs">{DEV}开发者,{ALL}全体等角色RKEY,不区分大小写</param>
/// <returns></returns>
protected bool HasRolesBusi(string roleRKEYs)
{
if (OString.ListInListNeedAll(roleRKEYs, GlbInfo.User.RolesUserIDS,",",true))
{
return true;
}
else return false;
} /// <summary>
/// 设置控件的属性值(无此属性或设置出错则返回FALSE)
/// </summary>
/// <param name="targetControl">目标控件</param>
/// <param name="PropName">区分大小写</param>
/// <param name="setValue">写入值</param>
/// <returns></returns>
public bool BaseSetControlProp(Control targetControl, string PropName, object setValue)
{
try
{
Type type = targetControl.GetType();
PropertyInfo per = type.GetProperty(PropName);
if (per != null)
{
per.SetValue(targetControl, setValue, null);
return true;
}
return false;
}
catch (Exception)
{
return false;
}
} /// <summary>
/// 设置控件的属性值(无此属性或设置出错则返回FALSE)
/// </summary>
/// <param name="targetObject"></param>
/// <param name="PropName"></param>
/// <param name="setValue"></param>
/// <returns></returns>
public bool BaseSetObjectProp(object targetObject, string PropName, object setValue)
{
try
{
Type type = targetObject.GetType();
PropertyInfo per = type.GetProperty(PropName);
if (per != null)
{
per.SetValue(targetObject, setValue, null);
return true;
}
return false;
}
catch (Exception)
{
return false;
}
} /// <summary>
/// 清空控件中的子控件值(有Value属性的会先设置Value,其他设置Text)
/// </summary>
/// <param name="targetControl">目标控件,如PANEL</param>
/// <param name="expChildNames">要排除的子控件名称,以(,)号分隔.</param>
public void BaseClearControl(Control targetControl, string expChildNames = "")
{
if (targetControl.Controls.Count > )
{
foreach (Control ctl in targetControl.Controls)
{
if (string.IsNullOrEmpty(expChildNames) || (("," + expChildNames + ",").IndexOf("," + ctl.Name + ",") < ))
{//没有指定过滤控件或者当前控件不是指定过滤控件
if (!(ctl is Label) && !(ctl is Button))
{
if (!BaseSetControlProp(ctl, "Value", null))
{
BaseSetControlProp(ctl, "Text", null);
}
}
}
}
}
} /// <summary>
/// 将指定控件的所有子控件设置为只读(无ReadOnly及JmReadOnly属性的设置Enabled)
/// </summary>
/// <param name="targetControl">目标控件</param>
/// <param name="readOnly">是否只读</param>
protected void BaseSetControlReadonly(Control targetControl, bool readOnly)
{
if (targetControl.Controls.Count > )
{
foreach (Control ctl in targetControl.Controls)
{
if (BaseSetControlProp(ctl, "ReadOnly", readOnly))
{
BaseSetControlProp(ctl, "Enabled", true);
}
else
{
if (BaseSetControlProp(ctl, "JmReadOnly", readOnly))
{
BaseSetControlProp(ctl, "Enabled", true);
}
else
{
//如果无ReadOnly及JmReadOnly属性,并且此控件没有子控件(如Panel下有子控件,则不能设置Panel为无效,而应该设置其子控件),则设置Enabled属性.
if (ctl.Controls.Count < )
{
BaseSetControlProp(ctl, "Enabled", !readOnly);
}
else
{
BaseSetControlReadonly(ctl, readOnly);
}
}
}
}
}
else
{
if (BaseSetControlProp(targetControl, "ReadOnly", readOnly))
{//成功设置了只读,放开Enabled属性
BaseSetControlProp(targetControl, "Enabled", true);
}
} } /// <summary>
/// 根据控件名称取得object对象
/// </summary>
/// <param name="objName"></param>
/// <returns></returns>
protected object GetObjInstance(string objName)
{
try
{
object o = this.GetType().GetField(objName, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.IgnoreCase).GetValue(this);
return o;
}
catch (Exception)
{
return null;
}
} /// <summary>
/// 在某个对象内根据控件名称获取子对象
/// </summary>
/// <param name="tagObject"></param>
/// <param name="objName"></param>
/// <returns></returns>
protected object GetObjInstanceIn(object tagObject, string objName)
{
try
{
Type type = tagObject.GetType();
object o = type.GetField(objName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.IgnoreCase).GetValue(this);
return o;
}
catch (Exception ex)
{
MyMsg.Information(ex.Message);
return null;
}
} #region 数据操作按钮通用方法 /// <summary>
/// 设置窗体中新增/编辑等符合命名规则的按钮状态(含权限判断)
/// </summary>
protected virtual void BaseResetCmdState()
{
SetObjectEnabled("CmdRcdNew", (EditStatus == ) && HasRights("add"));
SetObjectEnabled("CmdRcdBack", (CurBSEditPos >= ) && (CurBSPosition != CurBSEditPos));
SetObjectEnabled("CmdRcdCopyNew", (EditStatus == ) && HasRights("add"));
SetObjectEnabled("CmdRcdEdit", (EditStatus == ) && HasRights("edit"));
SetObjectEnabled("CmdRcdUndo", (EditStatus > ));
SetObjectEnabled("CmdRcdSave", (EditStatus > ) && (HasRights("add") || HasRights("edit")));
SetObjectEnabled("CmdRcdDelete", (EditStatus == ) && HasRights("delete"));
SetObjectEnabled("CmdRcdPreview", (EditStatus == ) && (HasRights("preview") || HasRights("print")));
SetObjectEnabled("CmdRcdPrint", (EditStatus == ) && HasRights("print"));
SetObjectEnabled("CmdRcdSync", (EditStatus == ) && HasRights("sync"));
} /// <summary>
/// 设置对象(Control/ToolStripItem)是否可用
/// </summary>
/// <param name="objName"></param>
/// <param name="enb"></param>
public void SetObjectEnabled(string objName, bool enb)
{
object tagO = GetObjInstance(objName);
if (tagO == null) return;
if (tagO is Control)
{
((Control)tagO).Enabled = enb;
}
else if (tagO is ToolStripItem)
{
((ToolStripItem)tagO).Enabled = enb;
}
} #endregion private void InitControlText(string ctlName,string tagText)
{
object o = GetObjInstance(ctlName);
if (o != null)
{
Type mtype = o.GetType();
if (mtype.GetProperty("Text") != null)
{
if (mtype.GetProperty("Text").GetValue(o, null) != null)
{
if (!string.IsNullOrEmpty(tagText)) mtype.GetProperty("Text").SetValue(o, tagText, null);
}
}
}
} /// <summary>
/// 对A12系列控件进行初始化作业(Datagridview中的列控件无法自动初始化)
/// </summary>
/// <param name="tagControls"></param>
private void DoA12ControlInits(Control.ControlCollection tagControls)
{
try
{
foreach (Control ctc in tagControls)
{
if (ctc != null)
{
Type tmpType = ctc.GetType();
if ((!ctc.HasChildren) || OString.StrInSplitString(tmpType.Name, "A12BtnTextBox,A12ComboBox"))
{
if (tmpType.Name == "A12ComboBox")
{
MethodInfo mm = tmpType.GetMethod("DoRequery");
mm.Invoke(ctc, null);
}
else if (tmpType.Name == "A12BtnTextBox")
{
MethodInfo mm = tmpType.GetMethod("DoInitilize");
mm.Invoke(ctc, null);
}
}
else
{
DoA12ControlInits(ctc.Controls);
}
}
}
}
catch (Exception)
{
}
} private void Fm11Base_Load(object sender, EventArgs e)
{
OnIniting = false; //加载多语言资源,设计时状态不运行
if (!DesignMode)
{
InitObjectsText(this);
//设置全局固定的多语言
InitControlText("TpgDataList", MultiLang.Surface(null, "FormTabList", "", true));
InitControlText("TpgDataDetail", MultiLang.Surface(null, "FormTabDetail", "", true));
InitControlText("CmdRcdNew", MultiLang.Surface(null, "CmdRcdNew", "", true));
InitControlText("CmdRcdBack", MultiLang.Surface(null, "CmdRcdBack", "", true));
InitControlText("CmdRcdCopyNew", MultiLang.Surface(null, "CmdRcdCopyNew", "", true));
InitControlText("CmdRcdEdit", MultiLang.Surface(null, "CmdRcdEdit", "", true));
InitControlText("CmdRcdUndo", MultiLang.Surface(null, "CmdRcdUndo", "", true));
InitControlText("CmdRcdSave", MultiLang.Surface(null, "CmdRcdSave", "", true));
InitControlText("CmdRcdDelete", MultiLang.Surface(null, "CmdRcdDelete", "", true));
InitControlText("CmdRcdPreview", MultiLang.Surface(null, "CmdRcdPreview", "", true));
InitControlText("CmdRcdPrint", MultiLang.Surface(null, "CmdRcdPrint", "", true));
InitControlText("CmdRcdSync", MultiLang.Surface(null, "CmdRcdSync", "", true));
string txtRequery = MultiLang.Surface(null, "CmdRequery", "", true);
InitControlText("CmdRequery01", txtRequery);
InitControlText("CmdRequery02", txtRequery);
InitControlText("CmdRequery03", txtRequery);
InitControlText("CmdRequery04", txtRequery);
InitControlText("CmdRequery05", txtRequery);
string txtFilter = MultiLang.Surface(null, "LabFilter", "", true);
InitControlText("LabFilter01", txtFilter);
InitControlText("LabFilter02", txtFilter);
InitControlText("LabFilter03", txtFilter);
InitControlText("LabFilter04", txtFilter);
InitControlText("LabFilter05", txtFilter);
}
//对A12系列控件进行初始化作业(如初始化下拉框控件数据)
DoA12ControlInits(this.Controls);
} /// <summary>
/// 初始化当前窗体内的文本(如果设置了多语言文件,则按多语言定义文件显示)
/// Tooltips控件不支持多语言显示
/// </summary>
/// <param name="tagObj">默认为this</param>
public void InitObjectsText(object tagObj)
{
Type curType = tagObj.GetType(); FieldInfo[] fieldInfos = curType.GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
string tmpText = string.Empty;
foreach (FieldInfo fi in fieldInfos)
{
object o = fi.GetValue(this);
if (o != null)
{
Type objType = o.GetType();
if (objType.GetProperty("Text") != null)
{
tmpText = MultiLang.Surface(this, fi.Name + ".Text", string.Empty);
if (!string.IsNullOrEmpty(tmpText)) objType.GetProperty("Text").SetValue(o, tmpText, null);
}
if (objType.GetProperty("Caption") != null)
{
tmpText = MultiLang.Surface(this, fi.Name + ".Caption", string.Empty);
if (!string.IsNullOrEmpty(tmpText)) objType.GetProperty("Caption").SetValue(o, tmpText, null);
}
if (objType.GetProperty("Hint") != null)
{
tmpText = MultiLang.Surface(this, fi.Name + ".Hint", string.Empty);
if (!string.IsNullOrEmpty(tmpText)) objType.GetProperty("Hint").SetValue(o, tmpText, null);
}
if (objType.GetProperty("SuperTip") != null)
{
tmpText = MultiLang.Surface(this, fi.Name + ".SuperTip", string.Empty);
if (!string.IsNullOrEmpty(tmpText)) objType.GetProperty("SuperTip").SetValue(o, tmpText, null);
}
}
} } private void Fm11Base_Resize(object sender, EventArgs e)
{
//此处避免子窗体切换时造成闪屏
if (this.IsMdiChild)
{
if (this.ParentForm.ActiveMdiChild == this)
{
this.WindowState = FormWindowState.Maximized;
}
else
{
this.WindowState = FormWindowState.Normal;
}
}
} /// <summary>
/// 根据提供的BindingSource,自动绑定窗体控件的数据来源(要求命名规则匹配);
/// <para>首先绑定勾选框属性(点击即更新数据源,DBNull默认为False)</para>
/// <para>再绑定Value及Text,所有绑定都默认从数据源带出格式验证</para>
/// 如果控件在Tag中指定了绑定字段{BindingField:RKEY},则使用指定值绑定
/// </summary>
/// <param name="ctc">要绑定的控件集合,如This.controls会查询整个窗体控件,如果有明确的定义,尽量缩小范围,如指定某个Panel或Page中的控件</param>
/// <param name="bindingSource">不指定时将使用窗体的当前绑定的BS</param>
/// <param name="bindingName">绑定名称,避免重复绑定</param>
/// <param name="bindlevel">绑定层次,此值在外部调用时无须变更,默认为0即可.递归绑定子控件时不会因为bindingName忽略绑定</param>
protected void AutoBindDataSource(Control.ControlCollection ctc, BindingSource bindingSource = null, string bindingName = "BSMaster", int bindlevel = )
{
string stText = MultiLang.Surface(null, "BindingControlDS", "正在为控件绑定数据来源", true);
try
{
//首次绑定时,如果窗体已经绑定过此数据源,则退出.如果是下级控件绑定,则继续
if ((HasBindBSNames.Contains(bindingName)) && (bindlevel == ))
{
return;
} if (bindingSource == null)
{
if (CurBindingSource == null)
{
SetMainStatus(stText + "error(current bs is null).");
return;
}
else
{
bindingSource = CurBindingSource;
}
}
SetMainStatus(stText + "...");
foreach (Control ctrl in ctc)
{
if (ctrl != null)
{
Type mtype = ctrl.GetType();
//A12BtnTxt包含子组件,是一个组合控件,应当成一个整体看待
if ((!ctrl.HasChildren) || (mtype.Name=="A12BtnTextBox") || (mtype.Name=="A12TextBox") || (mtype.Name == "A12ComboBox"))
{
string tagFieldName = string.Empty;
string ctrlTagString = OString.NZ2Str(ctrl.Tag);
string tagRlsControlName = OString.GetMidStr(ctrlTagString, "{UserNameLab:", "}").Trim();
//看下控件是否有TagBindField属性
if (mtype.GetProperty("TagBindField") != null)
{
object o = mtype.GetProperty("TagBindField").GetValue(ctrl,null);
if (o != null) tagFieldName = o.ToString();
}
//如果没有获取到,则从Tag中获取
if (string.IsNullOrEmpty(tagFieldName))
{
tagFieldName = OString.GetMidStr(ctrlTagString, "{BindingField:", "}").Trim();
}
//如果没有获取到,则从名称中截取
if (string.IsNullOrEmpty(tagFieldName))
{
if ((ctrl.Name.IndexOf("AB") == ) && (ctrl.Name.IndexOf("_") > ))
{
tagFieldName = ctrl.Name.Substring(ctrl.Name.IndexOf("_") + );
}
} if (!string.IsNullOrEmpty(tagFieldName))
{
try
{
Binding TmpBinding = null; if (mtype.Name == "A12ComboBox") //自定义下拉框控件直接绑定Value属性
{
TmpBinding = ctrl.DataBindings.Add("Value", bindingSource, tagFieldName, true);
}
else if (mtype.Name == "A12BtnTextBox")
{
TmpBinding = ctrl.DataBindings.Add("Value", bindingSource, tagFieldName, true);
}
else if (ctrl is DateTimePicker)
{
//日期时间控件直接绑定Text属性
TmpBinding = ctrl.DataBindings.Add("Text", bindingSource, tagFieldName, true,DataSourceUpdateMode.OnPropertyChanged);
}
else
{
if (mtype.GetProperty("Checked") != null)
{
TmpBinding = ctrl.DataBindings.Add("Checked", bindingSource, tagFieldName, true, DataSourceUpdateMode.OnPropertyChanged, );//当null时设置为0,不能为False,否则会出错.
}
else if (mtype.GetProperty("Value") != null)
{
TmpBinding = ctrl.DataBindings.Add("Value", bindingSource, tagFieldName, true);
}
else if (mtype.GetProperty("Text") != null)
{
TmpBinding = ctrl.DataBindings.Add("Text", bindingSource, tagFieldName, true);
}
}
if ((TmpBinding != null) && (!string.IsNullOrEmpty(tagRlsControlName)))
{
TmpBinding.BindingComplete += BaseBSBindingComplete;
}
}
catch (Exception)
{
continue;
}
}
//没有子控件的处理完成直接跳到下一个控件,否则检查子控件
continue;
}
else
{
AutoBindDataSource(ctrl.Controls, bindingSource, bindingName, );
}
//否则检查子控件
}
}
//首次绑定才记录此值,递归时下级控件绑定不变更
if (bindlevel == ) HasBindBSNames.Add(bindingName);
}
catch (Exception ex)
{
SetMainStatus(stText + "error:" + ex.Message);
}
finally
{
SetMainStatus("");
}
}
/// <summary>
/// 数据绑定交互后,对设置有{UserNameLab:的Tag属性的控件,根据其值(用户ID)关联显示用户其他信息
/// <para>{UserNameLab:Lab1}中Lab1即为显示额外信息的控件名称</para>
/// </summary>
/// <param name="sender"></param>
/// <param name="e">接受一个Bindingsource的BindingComplete事件</param>
protected void BaseBSBindingComplete(object sender, BindingCompleteEventArgs e)
{
if (e.BindingCompleteState == BindingCompleteState.Success)
{
string ctrlTagString = OString.NZ2Str(e.Binding.Control.Tag);
string tagRlControlName = OString.GetMidStr(ctrlTagString, "{UserNameLab:", "}").Trim();
if (!string.IsNullOrEmpty(tagRlControlName))
{
//绑定控件指定了自动关联控件
string userID = "system";
Type stype = e.Binding.Control.GetType();
if (stype.GetProperty("Text") != null)
{
userID = e.Binding.Control.Text;
} object tagO = GetObjInstance(tagRlControlName);
if (tagO != null)
{
try
{
string tagValue = string.Empty;
if (UserNameDispType == )
{
tagValue = userID;
}
else
{
List<object> tagUser = GlbInfo.GetSysUserInfo(userID, "UserName" + GlbInfo.Language + ",FullName" + GlbInfo.Language);
if (tagUser.Count > )
{
if (UserNameDispType == ) tagValue = OString.NZ2Str(tagUser[]);
else if (UserNameDispType == ) tagValue = OString.NZ2Str(tagUser[]);
else if (UserNameDispType == ) tagValue = userID + " - " + OString.NZ2Str(tagUser[]);
else if (UserNameDispType == ) tagValue = userID + " - " + OString.NZ2Str(tagUser[]);
}
} Type mtype = tagO.GetType();
if (mtype.GetProperty("Value") != null)
{
BaseSetObjectProp(tagO, "Value", tagValue);
}
else if (mtype.GetProperty("Text") != null)
{
BaseSetObjectProp(tagO, "Text", tagValue);
}
}
catch (Exception)
{ }
}
}
}
} #region 对话框显示应用程序作业状态
/// <summary>
/// 指定一个耗时任务监控窗体的运行参数, 其中RunningAction = delegate () { MethordName(bgwk); }
/// </summary>
protected class BgwkDef
{
public BackgroundWorker TagBgwk;
public Action RunningAction;
public int TProgMinimum = ;
public int TProgStep = ;
public int TProgMaximum = ;
public string RunningStatus;
} /// <summary>
/// 开始一个耗时较久的任务,调用前须先定义一个BgwkDef
/// </summary>
/// <param name="sBgwkDef"></param>
protected void BeginBgwork(BgwkDef sBgwkDef)
{
if (fm11BgwkStatus == null)
{
fm11BgwkStatus = new Fm11BgwkStatus();
}
if (fm11BgwkStatus != null)
{
fm11BgwkStatus.ProgMain.Minimum = sBgwkDef.TProgMinimum;
fm11BgwkStatus.ProgMain.Step = sBgwkDef.TProgStep;
fm11BgwkStatus.ProgMain.Maximum = sBgwkDef.TProgMaximum;
fm11BgwkStatus.TopLevel = false;
fm11BgwkStatus.Parent = this;
fm11BgwkStatus.Show();
fm11BgwkStatus.BringToFront();
fm11BgwkStatus.Left = (this.Width - fm11BgwkStatus.Width) / ;
fm11BgwkStatus.Top = (this.Height - fm11BgwkStatus.Height) / - ;
}
if (sBgwkDef.RunningAction == null)
{
MyMsg.Warning("系统后台任务必须指定作业方法,请检查!");
return;
} BackgroundWorker tagBgwk = sBgwkDef.TagBgwk ?? new BackgroundWorker();
tagBgwk.WorkerSupportsCancellation = true;
tagBgwk.WorkerReportsProgress = true;
tagBgwk.DoWork -= BgwkBase_DoWork;
tagBgwk.DoWork += BgwkBase_DoWork;
tagBgwk.ProgressChanged -= BgwkBase_ProgressChanged;
tagBgwk.ProgressChanged += BgwkBase_ProgressChanged;
tagBgwk.RunWorkerCompleted -= BgwkBase_RunWorkerCompleted;
tagBgwk.RunWorkerCompleted += BgwkBase_RunWorkerCompleted;
tagBgwk.RunWorkerAsync(sBgwkDef.RunningAction);
} protected void CancelBgwork(BackgroundWorker tagBgwk)
{
tagBgwk.CancelAsync();
} protected void BgwkBase_DoWork(object sender, DoWorkEventArgs e)
{
((Action)e.Argument).Invoke();
} protected void BgwkBase_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
if (fm11BgwkStatus != null)
{
fm11BgwkStatus.ProgMain.Value = e.ProgressPercentage > fm11BgwkStatus.ProgMain.Maximum ? fm11BgwkStatus.ProgMain.Maximum : e.ProgressPercentage;
fm11BgwkStatus.ProgMain.PerformStep();
fm11BgwkStatus.LabMessage.Text = e.UserState.ToString();
fm11BgwkStatus.LabMessage.Refresh();
}
SetMainStatus(e.UserState.ToString());
} protected void BgwkBase_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
{
}
if (fm11BgwkStatus != null)
{
fm11BgwkStatus.Close();
fm11BgwkStatus = null;
}
}
#endregion /// <summary>
/// 当前BS绑定的Datatable提交变更
/// </summary>
protected void BaseCurBSDTAccept()
{
if (CurBindingSource.DataSource is DataTable dtb)
{
dtb.AcceptChanges();
}
else if (CurBindingSource.DataSource is DataSet dsb)
{
if (!string.IsNullOrEmpty(CurBindingSource.DataMember))
{
dsb.Tables[CurBindingSource.DataMember].AcceptChanges();
}
}
} /// <summary>
/// 当前BS绑定的Datatable回滚变更,并放弃当前新增的行,此项须配合DGV的CancelEdit(),A12DataGridView使用其自带的Undo
/// </summary>
protected void BaseCurBSDTUndo()
{
if (CurBindingSource != null) CurBindingSource.CancelEdit();
if (CurBindingSource.Current != null)
{
DataRow dataRow = ((DataRowView)CurBindingSource.Current).Row;
dataRow.RejectChanges(); //放弃本行
} if (CurBindingSource.DataSource is DataTable dtb)
{
dtb.RejectChanges();
}
else if (CurBindingSource.DataSource is DataSet dsb)
{
if (!string.IsNullOrEmpty(CurBindingSource.DataMember))
{
dsb.Tables[CurBindingSource.DataMember].RejectChanges();
}
} } /// <summary>
/// 根据用户权限及操作条件刷新控件状态(基类无任何事件,需在继承事件上处理)
/// <para>此外会对tag中含有{UserNameLab:的控件进行关联显示用户名</para>
/// 设置权限请依照从大控件到小控件设置,以免前面设置的小控件属性被大控件属性覆盖.
/// </summary>
protected virtual void ResetControlStatus()
{
BaseResetCmdState();
} /// <summary>
/// 标记位置,刷新按钮状态(默认调用数据撤销,如果是A12DataGridView,请使用其自带的Undo,普通DGV需要先调用Dgv的CancelEdit())
/// </summary>
/// <param name="needDataUndo">是否需要撤销数据变更,如果是A12DataGridView,请使用其自带的Undo</param>
protected virtual void BaseCmdRcdUndo(bool needDataUndo = true)
{
SetMainStatus("..");
if (needDataUndo) BaseCurBSDTUndo();
CurBSEditPos = -;
EditStatus = ;
ResetControlStatus();
} }

FmBase.cs

在此基础上,就可以很好的进行进一步的扩展。

C# Winform下一个热插拔的MIS/MRP/ERP框架13(窗体基类)的更多相关文章

  1. C# Winform下一个热插拔的MIS/MRP/ERP框架15(窗体基类场景1)

    最基础的窗体基类其实是通过应用场景反推的结构. 以下是场景一: 单表应用,普通的数据,比如单位/颜色/特殊字典等使用者少的,无需过多控制的可以使用一个数据表格来管理. 和Excel表格差不多,批量修改 ...

  2. C# Winform下一个热插拔的MIS/MRP/ERP框架12(数据处理基类)

    作为ERP等数据应用程序,数据库的处理是重中之重. 在框架中,我封装了一个数据库的基类,在每个模组启动或窗体启动过程中,实例化一个基类即可调用CRUD操作(create 添加read读取 update ...

  3. C# Winform下一个热插拔的MIS/MRP/ERP框架11(启航)

    初学时,有了想法却完全不知道该从何下指,此序列将抛砖引玉,与大家共同学习进步. 一个程序的初始,必然是启动. 我的要求: 1.应用程序保持单例: 2.从配置文件加载一些基础数据进行初始化: 3.显示软 ...

  4. C# Winform下一个热插拔的MIS/MRP/ERP框架(简介)

    Programmer普弱哥们都喜欢玩自己的框架,我也不例外. 理想中,这个框架要易于理解.易于扩展.易于维护:最重要的,易于CODING. 系统是1主体框架+N模组的多个EXE/DLL组成的,在主体框 ...

  5. C# Winform下一个热插拔的MIS/MRP/ERP框架(多语言方案)

    个别时候,我们需要一种多语种切换方案. 我的方案是这样的: 1.使用文本文本存储多语言元素,应用程序启动时加载到内存表中: 2.应用程序启动时从配置文件加载语种定义: 3.所有窗体继承自一个Base基 ...

  6. C# Winform下一个热插拔的MIS/MRP/ERP框架14(自动更新)

    对于软件来说,启用自动更新是非常必要的. 根据软件的应用场景,我们可以设计不同的更新模型. 目前,IMES框架运行在.Net framework 4.0下面,使用的Win系统版本在Win7,域内管控, ...

  7. C# Winform下一个热插拔的MIS/MRP/ERP框架(通用控件)

    一直对商业控件不感冒, 结合日常工作, 我写了几个常用控件. 一.下拉框控件(仿Access下拉框:F4下拉,自动输入,支持单/多列显示),可在Datagridview中使用. 1.常规: 2.Dat ...

  8. C# Winform下一个热插拔的MIS/MRP/ERP框架16(窗体基类场景2)

    如果没有特别需求,和场景1一样只变更表名,主键字段,检测字段等名称,不需要写其它代码了. * 清单列表+单笔编辑/保存,适用于大多数基础资料管理以及简单的单据资料录入(当然,排版是要改一改的): * ...

  9. Winform框架中窗体基类的用户身份信息的缓存和提取

    在Winform开发中,有时候为了方便,需要把窗体的一些常规性的数据和操作函数进行封装,通过自定义基类窗体的方式,可以实现这些封装管理,让我们的框架统一化.简单化的处理一些常规性的操作,如这里介绍的用 ...

随机推荐

  1. Ajax 简单实例,其实就是js里面内容有些不同而已(转载)

    这些时间,瞎子也看得见,AJAX正大踏步的朝我们走来.不管我们是拥护也好,反对也罢,还是视而不见,AJAX像一阵潮流,席转了我们所有的人. 关于AJAX的定义也好,大话也好,早有人在网上发表了汗牛充栋 ...

  2. Excel VBA入门(六)过程和函数

    前面讲过,VBA代码有两种组织形式,一种就是过程(前面的示例中都在使用),另一种就是函数.其实过程和函数有很多相同之处,除了使用的关键字不同之外,还有不同的是: 函数有返回值,过程没有 函数可以在Ex ...

  3. centOS系统安装MySQL教程

    如何卸载CentOS系统自带MySQL 1.1. 查找以前是否装有MySQL 命令:rpm -qa|grep -i mysql 可以看到如下图的所示:(图片来自互联网,仅做参考使用) 说明系统自带: ...

  4. cocoapods使用问题集锦(2017-04)

    今天公司在公司新发的电脑上边安装cocoapod发现容易忘记的几个问题,感觉需要记录下来. 问题一:系统默认ruby镜像的卸载命令行 -->     gem sources --remove h ...

  5. 钉钉开发笔记(六)使用Google浏览器做真机页面调试

    注: 参考文献:https://developers.google.com/web/ 部分字段为翻译文献,水平有限,如有错误敬请指正 步骤1: 从Windows,Mac或Linux计算机远程调试And ...

  6. C++ 重载操作符- 02 重载输入输出操作符

    重载输入输出操作符 本篇博客主要介绍两个操作符重载.一个是 <<(输出操作符).一个是 >> (输入操作符) 现在就使用实例来学习:如何重载输入和输出操作符. #include ...

  7. Python守护进程(多线程开发)-乾颐堂

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 3 ...

  8. Rabbit MQ参考资料

    https://github.com/ServiceStack/rabbitmq-windows/blob/master/README.md https://github.com/rabbitmq/r ...

  9. Oracle 用户

    1.关于创建用户; 2.用户配置文件; 3.创建用户; 4.更改用户; 5.删除用户; 1.关于创建用户: 1.1 用户名:创建数据库用户必须具有 Create user 系统权限,必须指定用户名和密 ...

  10. U盘安装RedHat linux 5.3

    U盘安装RedHat linux 5.3 1.下载rhel-5.3-server-i386-dvd.iso文件: 2.下载绿色版UltraISO软件: 3.将rhel-5.3-server-i386- ...