Click here to Skip to main content
15,895,084 members
Articles / Web Development / ASP.NET

Required BoundField in GridView

Rate me:
Please Sign up or sign in to vote.
4.50/5 (5 votes)
31 May 2011CPOL2 min read 56.8K   8   4
Demonstration of a custom bound field that will allow validation.

Introduction

I like to use the ASP.NET GridView for administrative functions in my applications. Like editing and managing statuses, types, etc.., usually items that end up in drop down lists where there is a finite number of columns that need to be managed.

Recently, I thought it would be nice if I didn't have to create a TemplateField every time I wanted to use validation. The regular BoundField works very well and makes it easy to use the OrderedDictionaries to retrieve the original and new values so you can update your data source. I found this article that tells you how to create your own BoundField that inherits from the DataControlField. In my case, I didn't need to do this much work because I wasn't binding to different controls, I was just validating the current controls.

Here I am creating a new class and inheriting it from BoundField. By doing this, I don't have to deal with the databinding and value extraction from the controls when updating. I also have two properties that I have added: ErrorForColor and the NumericType which is an enum that I can use to add the appropriate validator.

C#
public class RequiredBoundField : BoundField
{
    const string NumericOnlyString = "NumericOnly";
    const string ErrorForeColorString = "ErrorForeColor";
    const string RequiredFieldErrorText = "*";
    const string NumericOnlyMessage = "Must be numeric";

    public virtual Color ErrorForeColor
    {
        get
        {
            object o = base.ViewState[ErrorForeColorString];
            if (o != null)
            {
                return (Color)o;
            }
            else
            {
                return Color.Red;
            }
        }
        set
        {
            base.ViewState[ErrorForeColorString] = value;
            OnFieldChanged();
        }
    }

    public virtual NumbericFieldType NumericType
    {
        get
        {
            object o = base.ViewState[NumericOnlyString];
            if (o != null)
            {
                return (NumbericFieldType)o;
            }
            else
            {
                return NumbericFieldType.Undefined;
            }
        }
        set
        {
            base.ViewState[NumericOnlyString] = value;
            OnFieldChanged();
        }
    }
}

At this point, we are going to override two functions: CreateField and InitializeDataCell. See the code below:

C#
protected override DataControlField CreateField()
{
    return new RequiredBoundField();
}

protected override void InitializeDataCell(DataControlFieldCell cell, 
                        DataControlRowState rowState)
{
    base.InitializeDataCell(cell, rowState);

    DataControlRowState state = rowState & DataControlRowState.Edit;
    if ((!ReadOnly && (state != DataControlRowState.Normal)))
    {
        TextBox textBox = cell.Controls[0] as TextBox;
        textBox.ID = this.DataField;

        RequiredFieldValidator validator = new RequiredFieldValidator();
        validator.ControlToValidate = this.DataField;
        validator.ErrorMessage = RequiredFieldErrorText;
        validator.ForeColor = this.ErrorForeColor;
        cell.Controls.Add(validator);

        if (this.NumericType != NumbericFieldType.Undefined)
        {
            CompareValidator compareValidator = new CompareValidator();
            compareValidator.ControlToValidate = this.DataField;
            compareValidator.ErrorMessage = NumericOnlyMessage;
            compareValidator.ForeColor = this.ErrorForeColor;
            compareValidator.Operator = ValidationCompareOperator.DataTypeCheck;

            switch (this.NumericType)
            {
                case NumbericFieldType.Integer:
                    compareValidator.Type = ValidationDataType.Integer;
                    break;
                case NumbericFieldType.Decimal:
                    compareValidator.Type = ValidationDataType.Double;
                    break;
            }                    
            
            cell.Controls.Add(compareValidator);
        }

    }
}

By using these key lines:

C#
TextBox textBox = cell.Controls[0] as TextBox;
textBox.ID = this.DataField; 

I can add the validators and use the ID to assign the validators to the appropriate text box. This will only work for cases where you would have used a BoundField. Not a CheckBoxField or something else like that.

OK, so now let's look at the implementation. First, in my case, I add the control namespace and assembly to the configuration file. Make sure to add it in the system.web element.

XML
<pages controlRenderingCompatibilityVersion="4.0" clientIDMode="AutoID">
   <controls>
      <add assembly="RequiredBoundFieldDemo" 
         namespace="RequiredBoundFieldDemo.Controls" 
         tagPrefix="custom" />
   </controls>
</pages>

Now that this is in the config file, you will see this in intellisense when you are trying to add columns to a GridView. Here is the code for my GridView:

ASP.NET
<asp:GridView ID="sampleGridView" runat="server" 
        GridLines="None" AutoGenerateColumns="False"
        DataKeyNames="Id" AutoGenerateEditButton="True" 
        CellPadding="5" 
        OnRowCancelingEdit="sampleGridView_RowCancelingEdit"
        OnRowEditing="sampleGridView_RowEditing" 
        OnRowUpdating="sampleGridView_RowUpdating">
    <Columns>
        <asp:BoundField HeaderText="Id" 
            DataField="Id" ReadOnly="true" />
        <custom:RequiredBoundField HeaderText="Required Text" 
            DataField="RequiredText" />
        <custom:RequiredBoundField HeaderText="Required Integer" 
            DataField="RequiredInteger"
            NumericType="Integer" />
        <custom:RequiredBoundField HeaderText="Required Decimal" 
            DataField="RequiredDecimal"
            NumericType="Decimal" />
        <asp:BoundField DataField="CreatedBy" 
            ReadOnly="true" HeaderText="Created By" />
        <asp:BoundField DataField="CreateTime" 
            ReadOnly="true" HeaderText="Date Created"
            DataFormatString="{0:d}" />
    </Columns>
</asp:GridView>

You can see that I am using a combination of regular BoundFields and my own that is named custom:RequiredBoundField. You also see on two of these columns that I have added the NumericType. Intellisense will also prompt you for the available options in the NumericType because it is an enum.

So now when you want to edit and update a row, you can use the e.NewValues Dictionary to retrieve the values that have been updated because the BoundField is taking care of all of that for you. See the code below:

C#
protected void sampleGridView_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
    int selectedId = (int)e.Keys[Id];

    using (SampleEntities context = new SampleEntities())
    {
        Demo demoObject = context.Demoes.FirstOrDefault(i => i.Id == selectedId);

        demoObject.RequiredText = Convert.ToString(e.NewValues[RequiredText]);
        demoObject.RequiredInteger = Convert.ToInt32(e.NewValues[RequiredInteger]);
        demoObject.RequiredDecimal = Convert.ToDecimal(e.NewValues[RequiredDecimal]);

        context.SaveChanges();

        sampleGridView.DataSource = context.Demoes.ToList();
    }

    sampleGridView.EditIndex = -1;
    sampleGridView.DataBind();

}

So that is it. Please feel free to download the demo project if you want to see a version that is running from start to finish. This will make my life easier from now on and I hope it does the same for you!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionGridView Edit Update Delete Using BoundField Pin
Ranjeet patil24-Aug-14 0:17
Ranjeet patil24-Aug-14 0:17 
QuestionUnable to override the "Visible" Property of a Bound Column Pin
moiztankiwala18-May-12 7:16
moiztankiwala18-May-12 7:16 
AnswerRe: Unable to override the "Visible" Property of a Bound Column Pin
Ben Kotvis18-May-12 8:14
Ben Kotvis18-May-12 8:14 
GeneralMy vote of 5 Pin
Monjurul Habib6-Jun-11 21:03
professionalMonjurul Habib6-Jun-11 21:03 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.