繼上篇文章winform 程序對界面上控件的統一控制【一】(賦值\清空\驗證… …) ,本篇文章將實現一個同樣功能的Component(組件)。
先看看組件的實現,如下所示:
代碼一
public partial class CtrlValidation : 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>
/// 可見下拉框屬性,下拉框為用戶控件
/// </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 partial class FrmChoose : Form
{
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 個功能函數。
本篇blog主要是為了闡述如何開發組件,如何給組件定義可視的屬性,並且定 義集合屬性。但願我講清楚了。