zoukankan      html  css  js  c++  java
  • 自定义控件学习(一)

    最近,看着公司自定义的控件,觉得自己应该学习这些东西,这样有助于自己基础知识的巩固,于是试着还原公司的代码,看自己是否有这样的功力。

      公司的控件大致有这样的用途:将控件放一个容器中,通过给自己定义控件绑定数据库中表的字段,然后根据业务的需求自动生成增删改查Sql语句,程序员可以将重点放在业务的分析处理中,尽可能的少写SQL语句。先不说这样的方法好不好,抱着学习的思想,我于是试着还原这些代码。

      现在想一下实现如此的功能:在自定义的一个容器控件中,放入自定义控件,有TextBox,Label,CheckBox等,然后,点击Button,自动生成AddSql、UpdateSql、SearchSql语句,然后直接执行这些语句,减少Sql语句的编写量,加快项目进展(这里Sql语句优化不考虑)。

      首先,控件开始考虑吧,我这里以TextBox为例子阐述自己的思路。

      对于TextBox,大家估计都比较熟悉,转到定义后可以看见

      TextBox : WebControl, IPostBackDataHandler, IEditableTextControl, ITextControl

      TextBox控件继承了一个WebControl类,实现了三个接口,非常漂亮的设计。

      WebControl类,微软官方的解释为:提供所有 Web 服务器控件的公共属性、方法和事件。通过设置在此类中定义的属性,可以控制 Web 服务器控件的外观和行为。由此可见,Web服务器控件应该都会继承或则个类了喔。

      为了防止Sql注入,微软强烈建议我们使用带参数的Sql语句,即如果是Sql Server 数据库,参数名应该是"@Name",如果是Oracle数据库,参数名应该是":Name"(似乎微软自身似乎不支持My Sql,如果支持的话,应该是"?")。因此,自动生成的AddSql与UpdateSql语句中,应该包括字段名,字段值;自动生成的SearchSql语句,应该更加复杂点,我们手写Sql语句时,会写 Name='刘德华' 或 Name like '%刘' 或 Name like '刘%' 或 Name like '%刘%',因此需要判断匹配符所在的位置。

      分析到现在,我们的xTextBox(自定义控件的名字)额外的属性有字段名、字段类型、查询类型、填充类型。

      首先定义查询类型类,因为类型是确定的,所以用枚举,代码如下

        public enum QueryTag
        {
            Exact,//精准查询 Name='刘德华'
            Dark,//模糊查询 Name like '%刘%'
            Start,//%前置模糊查询 Name like '%刘'
            End//%后置模糊查询 Name like '刘%'
        }
    

     现在分析,如何保存这些中间值(因为这些值本身不是太重要,我们需要得到的是处理后的值),这是值得考虑的。我们在学习三层架构的的时候,大都会把一个表的字段放在一个Model类中,这样处理的好处是我们只要得到一个Model,就可以从中取得我们需要的任一个值。因此,定义一个Field类,保存用以保存获取自定义控件的属性的值。那么自定义控件可能需要什么额外的属性呢?默认填充值得类型、数据库字段名、数据库字段值、查询标记。代码如下

      那么,现在有一个问题就是如何在容器中区分wTextBox与TextBox?

      其实,最先考虑的是根据类型名来区分

      如果asp:TextBox控件的ID为 txtASP,则txtASP.GetType().Name的值为TextBox

          如果wTextBox的ID为txtW,则txtW.GetType().Name为wTextBox

      如果我区分控件,则需要如下书写

    foreach (Control ctrl in testPanel.Controls)
               {
                   switch (ctrl.GetType().Name)
                   {
                       case "wTextBox":
                           break;
                       case "wLable":
                           break;
                       case "wCheckBox":
                           break;
               ......
    } }

      这种写法虽然可以很好的区分自定义控件以及微软的服务器控件,假设有10个自定义控件,则要10个case语句,原则上不好,因此,寻找另外一种方法。

      那么,我就参考TextBox实现方式,即实现某一个接口,因此可以让所有的自定义控件实现这个接口,那么,实现了自定义接口的控件便是自定义控件。问题解决了,不用具体区分是wTextBox还是wLable了。这里,我定义一个接口IBoundControl,让所有自定义的控件都去实现它。那么这个接口应该有什么功能呢。首先,这个接口可以得到一个自定义控件所有的属性,即可以得到Field类,其次,我们在进行数据填充的时候,需要给控件赋值,则需要一个方法,给控件赋值的方法。Field代码代码如下

    public class Field
        {
            // Fields
            public FillType FillType;//默认填充值
            public DisplayFormat Format;//现实形式 普通字符串 还是日期格式等
            public string Key;//数据库表的字段名 字段名 Name
            public string Name;//数据库表的字段名 字段名 Name
            public QueryTag QueryTag;//查询标记 生成查询语句用
            public DbType Type;//字段类型 
            public object Value;//数据库表的字段传递的值 字段值 张柏芝
    
            // Methods
            public Field()
            {
                this.Name = string.Empty;
                this.Key = string.Empty;
                this.Value = string.Empty;
                this.Type = DbType.String;
                this.QueryTag = QueryTag.Exact;
                this.Format = DisplayFormat.Normal;
                this.FillType = FillType.Null;
            }
            public Field(string strName, object strValue)
            {
                this.Name = strName;
                this.Value = strValue;
            }
            public Field(string strName, object strValue, DbType fieldType)
            {
                this.Type = fieldType;
            }
            public Field(string strName, string strKey, object strValue)
            {
                this.Key = strKey;
            }
            public Field(string strName, string strKey, object strValue, DbType fieldType)
            {
                this.Type = fieldType;
            }
            public override string ToString()
            {
                if (string.IsNullOrEmpty(this.Key))
                {
                    return this.Name;
                }
                return (this.Name + "-" + this.Key);
            }
        }
    IBoundControl接口代码如下:
     public interface IBoundControl
     {
       Field GetBoundField();
        void SetValue(string strValue);
     }

      此时,xTextBox代码已经出来了,代码如下

    public class xTextBox:TextBox,IBoundControl
        {
            #region 属性描述
            [DefaultValue(""), Description("绑定的字段名称")]
            public string wFieldName
            {
                get
                {
                    return (this.ViewState["wFieldName"] as string);
                }
                set
                {
                    this.ViewState["wFieldName"] = value;
                }
            }
    
            [DefaultValue("String"), Description("绑定的字段类型")]
            public DbType wFieldType
            {
                get
                {
                    string str = this.ViewState["wFieldType"] as string;
                    return (DbType)Enum.Parse(typeof(DbType), str);
                }
                set
                {
                    this.ViewState["wFieldType"] = value.ToString();
                }
            }
    
            [DefaultValue("Null"), Description("填充类型")]
            public FillType wFillType
            {
                get
                {
                    string str = this.ViewState["wFillType"] as string;
                    return (FillType)Enum.Parse(typeof(FillType), str);
                }
                set
                {
                    this.ViewState["wFillType"] = value.ToString();
                }
            }
    
            [Description("字段查询标记"), DefaultValue("Exact")]
            public QueryTag wQueryTag
            {
                get
                {
                    string str = this.ViewState["wQueryTag"] as string;
                    return (QueryTag)Enum.Parse(typeof(QueryTag), str);
                }
                set
                {
                    this.ViewState["wQueryTag"] = value.ToString();
                }
            } 
            #endregion
    
            public xTextBox()
            {
                this.wFieldName = "";
                this.wFieldType = DbType.String;
                this.wQueryTag = QueryTag.Exact;
                this.wFillType = FillType.Null;
            }
    
            public Field GetBoundField()
            {
                return new Field { 
                    Name = this.wFieldName,
                    Value = this.Text,
                    Type = this.wFieldType,
                    QueryTag = this.wQueryTag,
                    FillType = this.wFillType };
            }
    
            public void SetValue(string strValue)
            {
                this.Text = strValue;
            }
        }

      前面已经讲过了,我们是把控件放在一个特定的容器,然后在在这个容器中读取数据的,那么容器的唯一需要的功能便是读取自定义控件。当然为了区别asp:Panel,我们仍需要定义一个接口,让容器控件实现这个接口,接口的功能只有一个,得到所有自定义控件。

    public interface IBoundContainder
        {
            IList<IBoundControl> GetControls();
        }
    public class xPanel:Panel,IBoundContainder
        {
            public IList<IBoundControl> GetControls()
            {
                return this.GetControls(this);
            }
    
            public IList<IBoundControl> GetControls(Control container)
            {
                List<IBoundControl> list = new List<IBoundControl>();
                foreach (Control control in container.Controls)
                {
                    if (control.HasControls())
                    {
                        list.AddRange(this.GetControls(control));
                    }
                    else if (control is IBoundControl)
                    {
                        list.Add((IBoundControl)control);
                    }
                }
                return list;
            }
        }

    到此,xPanel与xTextBox已经完成,接下来会讲解如何利用自定义控件根据业务需求去完成增、改、查、显示功能。

  • 相关阅读:
    各操作系统各文件系统支持的最大文件的大小
    Java调用百度地图API
    Java面试宝典(3)Java基础部分
    Java7中的try-with-resources
    Spring学习笔记(6)——IoC的三种注入方式
    cmd中java的编译命令——java和javac、javap
    Spring学习笔记(14)——注解零配置
    java中多种方式解析xml
    双三次插值
    RCNN到faster RCNN 简介
  • 原文地址:https://www.cnblogs.com/xianrongbin/p/2877934.html
Copyright © 2011-2022 走看看