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已经完成,接下来会讲解如何利用自定义控件根据业务需求去完成增、改、查、显示功能。

  • 相关阅读:
    MSSQL大量数据时,建立索引或添加字段后保存更改超时该这么办
    POJ 3261 Milk Patterns (后缀数组)
    POJ 1743 Musical Theme (后缀数组)
    HDU 1496 Equations (HASH)
    694. Distinct Substrings (后缀数组)
    POJ 1222 EXTENDED LIGHTS OUT (枚举 或者 高斯消元)
    POJ 1681· Painter's Problem (位压缩 或 高斯消元)
    POJ 1054 The Troublesome Frog (hash散列)
    HDU 1716 排列2
    HDU 4405 Aeroplane chess (概率DP & 期望)
  • 原文地址:https://www.cnblogs.com/xianrongbin/p/2877934.html
Copyright © 2011-2022 走看看