继上篇文章winform 程序对界面上控件的统一控制【一】(赋值\清空\验证……) ,本篇文章将实现一个同样功能的Component(组件)。
先看看组件的实现,如下所示:

{
public CtrlValidation()
{
InitializeComponent();
typeCache = new TypeCache();
}
public CtrlValidation(IContainer container)
{
container.Add(this);
InitializeComponent();
typeCache = new TypeCache();
}
TypeCache typeCache;
List<RealSailing.UI.Utils.SetControl> ctrlCollect = new List<RealSailing.UI.Utils.SetControl>();
[Description("控件集合")]
[Editor(typeof(DropEditor), typeof(UITypeEditor))]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public List<RealSailing.UI.Utils.SetControl> CtrlCollect
{
get
{
return ctrlCollect;
}
set
{
ctrlCollect = value;
}
}
private object dataSource;
[Category("CatData"), DefaultValue((string)null), RefreshProperties(RefreshProperties.Repaint),
Description("DataGridDataSourceDescr"), AttributeProvider(typeof(IListSource))]
public object DataSource
{
get
{
return this.dataSource;
}
set
{
if (((value != null) && !(value is IList)) && !(value is IListSource))
{
throw new ArgumentException("BadDataSourceForComplexBinding");
}
if ((this.dataSource == null) || !this.dataSource.Equals(value))
{
if (((value == null) || (value == Convert.DBNull)) && ((this.DataMember != null) && (this.DataMember.Length != 0)))
{
this.dataSource = null;
this.DataMember = "";
}
else
{
if (value != null)
{
this.dataSource = value;
}
}
}
}
}
private string dataMember;
[DefaultValue((string)null), Description("DataGridDataMemberDescr"),
Category("CatData"),
Editor("System.Windows.Forms.Design.DataMemberListEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
public string DataMember
{
get
{
return this.dataMember;
}
set
{
if ((this.dataMember == null) || !this.dataMember.Equals(value))
{
this.dataMember = value;
}
}
}
#region 提供方法
/// <summary>
/// 必填项是否为空,true表示不为空,FALSE表示为空
/// </summary>
/// <returns></returns>
public bool CheckIsNull()
{
foreach (RealSailing.UI.Utils.SetControl ctrl in ctrlCollect)
{
object[] obj = new object[] { ctrl };
TypeProcess _process = TypeFactory.CreateType(ctrl.ControlName.GetType().Name, obj, ctrl.ToString(), typeCache);
bool editnull = _process.CheckNull();
if (!editnull)
return editnull;
}
return true;
}
/// <summary>
/// 输入框的格式是否正确,true表示正确,FALSE表示不正确
/// </summary>
/// <returns></returns>
public bool CheckIsFormate()
{
foreach (RealSailing.UI.Utils.SetControl ctrl in ctrlCollect)
{
if (ctrl.ControlName.GetType().Equals(typeof(DevExpress.XtraEditors.TextEdit)))
{
object[] obj = new object[] { ctrl };
TypeProcess _process = TypeFactory.CreateType(ctrl.ControlName.GetType().Name, obj, ctrl.ToString(), typeCache);
bool editformate = _process.CheckFormate();
if (!editformate)
return editformate;
}
}
return true;
}
/// <summary>
/// 清空画面
/// </summary>
public void SetCtrlClear()
{
ctrlCollect.ForEach(ctrl =>
{
object[] obj = new object[] { ctrl };
TypeProcess _process = TypeFactory.CreateType(ctrl.ControlName.GetType().Name, obj, ctrl.ToString(), typeCache);
_process.SetCtrlClear();
});
}
/// <summary>
/// 设置控件可用状态
/// </summary>
/// <param name="enable"></param>
public void SetCtrlEnable(bool enable)
{
ctrlCollect.ForEach(ctrl =>
{
object[] obj = new object[] { ctrl };
TypeProcess _process = TypeFactory.CreateType(ctrl.ControlName.GetType().Name, obj, ctrl.ToString(), typeCache);
_process.SetCtrlEnable(enable);
});
}
/// <summary>
/// 设置控件默认值
/// </summary>
public void SetCtrlDefault()
{
ctrlCollect.ForEach(ctrl =>
{
object[] obj = new object[] { ctrl };
TypeProcess _process = TypeFactory.CreateType(ctrl.ControlName.GetType().Name, obj, ctrl.ToString(), typeCache);
_process.SetCtrlDefault();
});
}
/// <summary>
/// 清除错误提示信息
/// </summary>
public void ClearErrText()
{
ctrlCollect.ForEach(ctrl =>
{
object[] obj = new object[] { ctrl };
TypeProcess _process = TypeFactory.CreateType(ctrl.ControlName.GetType().Name, obj, ctrl.ToString(), typeCache);
_process.ClearErrText();
});
}
/// <summary>
/// 将数据行的值映射到文本编辑框中
/// </summary>
/// <param name="row"></param>
public void LoadEditRowToText(DataRow row)
{
if (row != null)
{
ctrlCollect.ForEach(ctrl =>
{
object[] obj = new object[] { ctrl };
TypeProcess _process = TypeFactory.CreateType(ctrl.ControlName.GetType().Name, obj, ctrl.ToString(), typeCache);
_process.LoadToText(row);
});
}
}
/// <summary>
/// 将编辑框中的数据赋给数据行
/// </summary>
/// <param name="row"></param>
public void SetCtrlTextToEditRow(DataRow row)
{
if (row != null)
{
ctrlCollect.ForEach(ctrl =>
{
object[] obj = new object[] { ctrl };
TypeProcess _process = TypeFactory.CreateType(ctrl.ControlName.GetType().Name, obj, ctrl.ToString(), typeCache);
_process.SetTextToRow(row);
});
}
}
#endregion
}
在上面的CtrlValidation类型中,提供了三个属性,DataSource和DataMember属性为数据绑定属性,和普通的.net控件一样,绑定到数据对象,不过本例中只能绑定到DataSet,并且需要指定它的DataTable。最为重要的是CtrlCollect属性,其类型为List<RealSailing.UI.Utils.SetControl>,表示控件的集合。并且该属性设置了Editor特性(指定用来更改属性的编辑器。无法继承此类。(MSDN))。并用DropEditor和基类型UITypeEditor初始化EditorAttribute类的新实例。接下来我们看看DropEditor类型,如何的实现:

/// 可见下拉框属性,下拉框为用户控件
/// </summary>
public class DropEditor : UITypeEditor
{
/// <summary>
/// 获取由 EditValue 方法使用的编辑器样式
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
{
if (context != null && context.Instance != null)
{
return UITypeEditorEditStyle.Modal;
}
return base.GetEditStyle(context);
}
/// <summary>
/// 使用指定的服务提供程序和上下文编辑指定对象的值。
/// </summary>
/// <param name="context">可用于获取附加上下文信息的 ITypeDescriptorContext。</param>
/// <param name="provider">IServiceProvider,通过它可能获得编辑服务。</param>
/// <param name="value">正在编辑的值的实例。</param>
/// <returns>新的对象值。如果该对象的值尚未更改,则这应返回与传递给它的对象相同的对象</returns>
public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
{
//为 UITypeEditor 提供一个接口,用于显示 Windows 窗体,或者在设计模式下在属性网格控件的下拉区域中显示控件。
IWindowsFormsEditorService iws = (IWindowsFormsEditorService)provider.GetService(
typeof(IWindowsFormsEditorService));
if (iws != null)
{
using (FrmChoose UIControl = new FrmChoose(context, (List<RealSailing.UI.Utils.SetControl>)value))
{
if (iws.ShowDialog(UIControl) == DialogResult.OK)
{
value = UIControl.Value;
context.OnComponentChanged();
}
}
}
return value;
}
}
DropEditor继承UITypeEditor(自提供可用于设计值编辑器的基类,这些编辑器可提供用户界面 (UI),用来表示和编辑所支持的数据类型的对象值。(MSDN))类型。并重写GetEditStyle( 获取由 EditValue 方法使用的编辑器样式)和EditValue(使用 GetEditStyle 方法所指示的编辑器样式编辑指定对象的值。)方法,前者返回UITypeEditorEditStyle,得到此编辑器的样式,本例中的选择的是Modal样式,显示一个省略号 (...) 按钮;后者返回object类型,表示编辑对象的值。在EditValue方法中,调用一个窗体FrmChoose,给CtrlValidation中的属性CtrlCollect赋值。再来看看FrmChoose窗体时如何实现的?

{
public FrmChoose()
{
InitializeComponent();
}
/// <summary>
///
/// </summary>
/// <param name="context"></param>
/// <param name="value"></param>
public FrmChoose(ITypeDescriptorContext context, List<RealSailing.UI.Utils.SetControl> value)
{
InitializeComponent();
this.SetStyle(System.Windows.Forms.ControlStyles.DoubleBuffer | System.Windows.Forms.ControlStyles.UserPaint | System.Windows.Forms.ControlStyles.AllPaintingInWmPaint, true);
this.BackColor = System.Drawing.SystemColors.Control;
if (0 != value.Count)
{
control = value;
foreach (object c in context.Container.Components)
{
if (c.GetType().BaseType.Equals(typeof(RealSailing.DataSet.BaseDataSet)))
FillCombFiled(context, c);
}
}
else
{
RealSailing.UI.Utils.SetControl setControl;
foreach (object c in context.Container.Components)
{
if (arrType.Contains(c.GetType()))
{
setControl = new RealSailing.UI.Utils.SetControl
{
ControlName = c,
NullAble = false,
Default = null,
Formate = "",
KeyFiled = false,
FiledName = ""
};
control.Add(setControl);
}
else if (c.GetType().BaseType.Equals(typeof(RealSailing.DataSet.BaseDataSet)))
{
FillCombFiled(context, c);
}
}
}
this.gcSelect.DataSource = control;
}
/// <summary>
/// 用数据集中的列填充ComboBoxEdit控件
/// </summary>
/// <param name="context"></param>
/// <param name="c"></param>
private void FillCombFiled(ITypeDescriptorContext context, object c)
{
RealSailing.DataSet.BaseDataSet myDs = c as RealSailing.DataSet.BaseDataSet;
Type t = context.Instance.GetType();
System.Reflection.PropertyInfo p = t.GetProperty("DataMember");
object obj = p.GetValue(context.Instance, null);
string table = obj == null ? "" : obj.ToString();
if (myDs != null && !string.IsNullOrEmpty(table))
{
DataColumnCollection cols = myDs.Tables[table].Columns;
if(!cols.Contains(" "))
cols.Add(" ", typeof(string));
combFiled.Items.Clear();
foreach (DataColumn col in cols)
{
combFiled.Items.Add(col.ColumnName);
}
}
}
/// <summary>
/// 验证控件类型
/// </summary>
ArrayList arrType = new ArrayList
{
typeof(DevExpress.XtraEditors.LookUpEdit),
typeof(DevExpress.XtraEditors.TextEdit),
typeof(DevExpress.XtraEditors.DateEdit),
typeof(DevExpress.XtraEditors.ComboBoxEdit),
typeof(RealSailing.UI.Common.UCSysParaslkEdit),
typeof(RealSailing.UI.Control.TextBoxEx),
typeof(RealSailing.UI.Control.MemoEditEx),
typeof(RealSailing.UI.Common.UCComboBox),
typeof(RealSailing.UI.Control.PopuLookUpedit),
typeof(RealSailing.UI.Control.UCTextEdit)
};
/// <summary>
/// 控件验证项
/// </summary>
List<RealSailing.UI.Utils.SetControl> control = new List<RealSailing.UI.Utils.SetControl>();
/// <summary>
/// 设置的值
/// </summary>
public List<RealSailing.UI.Utils.SetControl> Value
{
get
{
return control;
}
}
private void btnOk_Click(object sender, EventArgs e)
{
this.Refresh();
this.Close();
}
private void btnCancel_Click(object sender, EventArgs e)
{
this.Close();
}
}
说明:
(1)该窗体上只包括一个GridControl(Devexpress)控件,并且在gridview中添加了一个ComboBoxEdit控件,用于选择该控件所绑定到的字段(前提是给CtrlValidation类型中的DataSource何DataMember属性赋过值,本类型中的FillCombFiled方法会通过反射,获取DataSet中DataTable的列,从而绑定到Gridview中ComboBoxEdit控件的Items属性中)。
(2)窗体中定义了一个ArrayList类型的arrType,该ArrayList中存放的是控件的类型,表名只对该类型的控件做处理,而其他类型的控件则不作处理。
(3)在FrmChoose有参构造函数中,会更具组件CtrlValidation的上下文,遍历窗体上的所有控件,并且将控件类型在arrType列表中的控件,添加到控件集合control中。
实现效果如图1示:

图1
这种的实现方式,比较上篇blog的实现方式,更加的方便。 在窗体设计时,将CtrlValidation组件拖入,便会自动加载需要控制的控件(有arrType列表中的控件类型决定)。在CtrlValidation属性中,设置集合属性CtrlCollect,将会弹出如图1所示的画面。点击确定完成控制属性的设置。再就可以调用该组件另外的8个功能函数。