使用双向绑定动态编辑任意对象内容(二)
上一篇中,为了达动动态编辑任意对象,我创建了四个辅助对象,分别是:
字段说明特性对象:ColumnDescriptionAttribute
数据源特性:DataSourceAttribute
数据源项对象:DataItem
隐藏属性特性:HideAttribute
下面我们开始运用这四个对象来完成计划的任务。首先我们来看下一般的编辑界面都有哪些属性及参数,下面就是一个典型的编辑界面:

图1:典型的编辑界面
如上图,共有六个区域:
区域1与区域4:字段标题
区域2与区域5:编辑控件
区域3:列分隔区
还有以下参数:
控件编辑区宽度:蓝色区域宽度
边距:蓝色区域与红色区域之间
标题长度:区域1与区域4的宽度
控件宽度:区域2与区域5的宽度
分隔间隔:区域3的宽度
首先来创建两个对照表:
类型与控件对照表
Boolean CheckBox
DateTime DateTimePicker
Int16 NumericUpDown
Int32 NumericUpDown
Int64 NumericUpDown
String TextBox
对应的代码实现
System.Collections.Generic.Dictionary dicTypeCtrl = new Dictionary(); dicTypeCtrl.Add(typeof(bool), typeof(CheckBox)); dicTypeCtrl.Add(typeof(DateTime), typeof(DateTimePicker)); dicTypeCtrl.Add(typeof(Int64), typeof(NumericUpDown)); dicTypeCtrl.Add(typeof(Int16), typeof(NumericUpDown)); dicTypeCtrl.Add(typeof(Int32), typeof(NumericUpDown));
控件与绑定属性对照表
CheckBox Checked
DateTimePicker Value
ComboBox SelectedValue
NumericUpDown Value
TextBox Text
对应代码实现
System.Collections.Generic.Dictionary dicBindingProp = new Dictionary(); dicBindingProp.Add(typeof(CheckBox).FullName, "Checked"); dicBindingProp.Add(typeof(DateTimePicker).FullName, "Value"); dicBindingProp.Add(typeof(ComboBox).FullName, "SelectedValue"); dicBindingProp.Add(typeof(NumericUpDown).FullName, "Value"); dicBindingProp.Add(typeof(TextBox).FullName, "Text");
有了上面两个对照表,我们拿到一个属性,就可以依次拿到编辑的控件,继而拿到绑定的属性。
下面是一个完整的代码示例:
namespace Guaik.WinForm
{
///
/// 自动布局,Guaik.com提供
///
public class AutoLayout
{
#region 布局
int _ControlWidth = 150;
///
/// 控件宽度
///
public int ControlWidth
{
get
{
return _ControlWidth;
}
set
{
_ControlWidth = value;
}
}
int _CaptionWidth = 100;
///
/// 标题宽度
///
public int CaptionWidth
{
get
{
return _CaptionWidth;
}
set
{
_CaptionWidth = value;
}
}
int _LineHeight = 23;
///
/// 行高
///
public int LineHeight
{
get
{
return _LineHeight;
}
set
{
_LineHeight = value;
}
}
int _SeparatedWidth = 50;
///
/// 分隔宽度
///
public int SeparatedWidth
{
get
{
return _SeparatedWidth;
}
set
{
_SeparatedWidth = value;
}
}
Point _StartPoint = new Point(5, 5);
///
/// 起始点
///
public Point StartPoint
{
get
{
return _StartPoint;
}
set
{
_StartPoint = value;
}
}
#endregion
public AutoLayout()
{
//默认的类型与控件对照表
dicTypeCtrl.Add(typeof(bool), typeof(CheckBox));
dicTypeCtrl.Add(typeof(DateTime), typeof(DateTimePicker));
dicTypeCtrl.Add(typeof(Int64), typeof(NumericUpDown));
dicTypeCtrl.Add(typeof(Int16), typeof(NumericUpDown));
dicTypeCtrl.Add(typeof(Int32), typeof(NumericUpDown));
//默认的控件绑定属性对照表
dicBindingProp.Add(typeof(CheckBox).FullName, "Checked");
dicBindingProp.Add(typeof(DateTimePicker).FullName, "Value");
dicBindingProp.Add(typeof(ComboBox).FullName, "SelectedValue");
dicBindingProp.Add(typeof(NumericUpDown).FullName, "Value");
dicBindingProp.Add(typeof(TextBox).FullName, "Text");
}
System.Collections.Generic.Dictionary dicBindingProp = new Dictionary();
System.Collections.Generic.Dictionary dicTypeCtrl = new Dictionary();
#region 扩展方法
///
/// 添加新的类型与控件对照项
///
///
///
public void AppendTypeControlMap(Type type, Control ctrl)
{
dicTypeCtrl[type] = ctrl.GetType();
}
///
/// 添加新的控件绑定项
///
///
///
public void AppendControlBindingName(Control ctrl, String propName)
{
dicBindingProp[ctrl.GetType().FullName] = propName;
}
#endregion
#region 开始布局
///
/// 开始布局
///
/// 显示的容器
/// 被编辑的对象
/// 控件后新一行的起始位置
public Point Layout(Control container, Object editObject)
{
if (container == null || editObject == null) return StartPoint;
int currentLineY = StartPoint.Y;//当前Y坐标
int currentX = StartPoint.X;//当前X坐标
//清空当前的已有的控件
container.Controls.Clear();
Type t = editObject.GetType();
PropertyInfo[] props = t.GetProperties();
int lineCtrl = 0;
Label caption = null;
Object[] objs = null;
String bindName = null;
Control editCtrl = null;
ColumnDescriptionAttribute cda = null;
DataSourceAttribute dataSource = null;
//添加一行新控件需要的总宽度
int sumWidth = CaptionWidth + ControlWidth;
//开始布局
foreach (System.Reflection.PropertyInfo prop in props)
{
//查看是否需要保护的属性
objs = prop.GetCustomAttributes(typeof(HideAttribute), true);
if (objs != null && objs.Length > 0) continue;
//检查是否为简单类型
if (!(prop.PropertyType.IsValueType || prop.PropertyType == typeof(string))) continue;
dataSource = null;
//检查一行的剩余的空间是否足以新加入一个编辑控件
if (container.Size.Width < (sumWidth + StartPoint.X + currentX))
{
lineCtrl = 0;
currentX = StartPoint.X;
currentLineY += LineHeight;
}
else
{
lineCtrl++;
}
objs = prop.GetCustomAttributes(typeof(ColumnDescriptionAttribute), true);
if (objs != null && objs.Length > 0) cda = (ColumnDescriptionAttribute)objs[0];
objs = prop.GetCustomAttributes(typeof(DataSourceAttribute), true);
if (objs != null && objs.Length > 0) dataSource = (DataSourceAttribute)objs[0];
//数据源不为空
if (dataSource != null)
{
ComboBox comoBox = new ComboBox();
comoBox.DataSource = dataSource.GetSource();
comoBox.DisplayMember = "Name";
comoBox.ValueMember = "Value";
editCtrl = comoBox;
}
else
{
editCtrl = GetControlByType(prop.PropertyType);
}
//额外的处理
if( editCtrl is NumericUpDown)
{
((NumericUpDown)editCtrl).Maximum = int.MaxValue;
((NumericUpDown)editCtrl).Minimum = int.MinValue;
}
//得到绑定的属性名
bindName = GetBindingProperty(editCtrl.GetType().FullName);
caption = new Label();
caption.Text = (cda == null || String.IsNullOrEmpty(cda.Description)) ? prop.Name : cda.Description;
caption.Location = new Point(currentX, currentLineY);
editCtrl.DataBindings.Add(new Binding(bindName, editObject, prop.Name));
editCtrl.Location = new Point(currentX + CaptionWidth, currentLineY);
editCtrl.Width = ControlWidth;
editCtrl.Enabled = (cda == null || !cda.ReadOnly);
container.Controls.Add(caption);
container.Controls.Add(editCtrl);
currentX += CaptionWidth + ControlWidth + SeparatedWidth;
}
return new Point(StartPoint.X, currentLineY + LineHeight);
}
#endregion
#region 根据类型得以编辑的控件
///
/// 根据类型得以编辑的控件
///
///
///
protected Control GetControlByType(Type type)
{
Type ctrlType = null;
if( dicTypeCtrl.ContainsKey(type) ) ctrlType = dicTypeCtrl[type];
if (ctrlType == null) ctrlType = typeof(TextBox);
return (Control)ctrlType.Assembly.CreateInstance(ctrlType.FullName);
}
#endregion
#region 根据控件全名得到绑定的属性
///
/// 根据控件全名得到绑定的属性
///
/// 属性全名
///
protected String GetBindingProperty(string ctrlFullName)
{
return dicBindingProp[ctrlFullName];
}
#endregion
}
}
有了这个类后,它就帮助我们完成编辑代码的功能了。并且能自动适应容器的宽度,自动适应的创建从列输入控件。但这个方法也有不足的地方,比如现在所有的控件都是固定的ControlWidth宽度,没有做到自定义控件宽度;也没有做到排版功能。但实现这个也是很方便的,比如自定义宽度,可以创建一个新的辅助对象,用来自定义宽度,之后创建控件时,使用自定义宽度,这样就可以达到了。
相关文章:
使用双向绑定动态编辑任意对象内容(一)
使用反射简化日常操作
- 1. 参数计数不匹配2010-02-06
- 2. 通过代码访问共享目录2009-11-03
- 3. 使用双向绑定动态编辑任意对象内容(二)2009-06-29
- 4. 使用双向绑定动态编辑任意对象内容(一)2009-06-26





