使用双向绑定动态编辑任意对象内容(二)

      上一篇中,为了达动动态编辑任意对象,我创建了四个辅助对象,分别是:
            字段说明特性对象: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宽度,没有做到自定义控件宽度;也没有做到排版功能。但实现这个也是很方便的,比如自定义宽度,可以创建一个新的辅助对象,用来自定义宽度,之后创建控件时,使用自定义宽度,这样就可以达到了。

相关文章:
      使用双向绑定动态编辑任意对象内容(一)
      使用反射简化日常操作
     

Tag标签: 反射
发表于 2009-06-29 15:59:18 收藏 所属分类: C# 网摘收藏
相关文章: