Dynamically Templated GridView with ITemplate Interface.

Writing a class which implements ITemplate
Here is the skeleton of class DynamicallyTemplatedGridViewHandler implementing ITemplate with a list of data members and methods.

Listing 2

public class DynamicallyTemplatedGridViewHandler : ITemplate
{
ListItemType ItemType;
string FieldName;
string InfoType;

public DynamicallyTemplatedGridViewHandler(ListItemType Item_type,
string field_name, string control_type);
public void InstantiateIn(System.Web.UI.Control Container);
private void OnDataBinding(object sender, EventArgs e);
}This class has three data members:

ListItemType ItemType;
string FieldName;
string InfoType;ItemType keeps the type of a list item type: Item, EditItem, Header, Footer, AlternatingItem, Pager, SelecetdItem or Separator. In this demo version we need only three of these; we need Header (For heading of each column), Item (for showing fields when GridView will be in normal mode) and EditItem (for showing fields when GridView will be in Edit mode).

FieldName keeps the name of each template field that will be displayed in the header.

InfoType keeps an indicator in string form for a type of information within a template field i.e. whether a template field has information of "Command" or "String" so that later data retrieval and data binding of that particular child control will be made accordingly. A "Command" (Edit, Delete, and Insert) requires instantiation in the Button control while he "String" requires a Label or TextBox.

Now, coming to the member methods listed above, there is a constructer which simply sets the aforementioned data members with those passed as parameters.

Listing 3

public DynamicallyTemplatedGridViewHandler(ListItemType item_type, string field_name,
string control_type)
{
ItemType = item_type;
FieldName = field_name;
InfoType = info_type;
}Here is the explanation of InstantiateIn the only method of ITemplate being implemented by our class DynamicallyTemplatedGridViewHandler.

InstantiateIn

InstantiateIn ensures that the list item type of each template is created in its appropriate control. For better understanding of functionality of this method see its name "InstantiateIn." It means "Instantiate Item In Literal/Label/TextBox/Button/." The choice will be according to the requirement. Like in the case of a Header, it is instantiated in Literal control as shown in this part of the implementation of InstantiateIn.

InstantiateIn takes a "Container," a Control type object as a parameter. Container's control collection is filled with all controls in which items of each type are instantiated. Its implementation in the current scenario is a little lengthy, yet it is quite easy as we have to do a similar type of job with each control; instantiate it, set its text property with FieldName and add it into Container's control collection.

For example, below the code of InstantiateIn shows that if the ItemType is a Header, then it creates a literal object called header_literal. After making it bold, set the text property of header_literal with FieldName. Finally, add this control to the control collection of the Container control passed as parameter to InstantiateIn method.

Similarly, we have to write instantiation code for ItemType if it is "Item" and "EditItem." In case the ItemType is "Item" (fields look when GridView is in normal mode), we need one more check inside it to see that InfoType tells whether the Item will be instantiated with a Button (Edit, Insert, and Delete) or Label. If InfoType is a Button then it creates three buttons for the aforementioned tasks. It is simple to do; create a button object, set its all properties accordingly, also add the button's click event handler and finally, add it into the control collection of the control (Container) passed as an argument.

Listing 4

public void InstantiateIn(System.Web.UI.Control Container)
{
switch (ItemType)
{
case ListItemType.Header:
Literal header_ltrl = new Literal();
header_ltrl.Text = "" + FieldName + "";
Container.Controls.Add(header_ltrl);
break;
case ListItemType.Item:
switch (InfoType)
{
case "Button":
ImageButton edit_button = new ImageButton();
edit_button.ID = "edit_button";
edit_button.ImageUrl = "~/images/edit.gif";
edit_button.CommandName = "Edit";
edit_button.Click += new ImageClickEventHandler(edit_button_Click);
edit_button.ToolTip = "Edit";
Container.Controls.Add(edit_button);
/*Similarly, add button for delete just set its
command to equal to "Delete." It is important to know when
"insert" button is added, its CommandName is set to "Edit" like
that of the "edi" button because we want the GridView to enter into
Edit mode and this time we also want the text boxes for corresponding fields
empty*/ ImageButton insert_button = new ImageButton();
insert_button.ID = "insert_button";
insert_button.ImageUrl = "~/images/insert.bmp";
insert_button.CommandName = "Edit";
insert_button.ToolTip = "Insert";
insert_button.Click += new ImageClickEventHandler(insert_button_Click);
Container.Controls.Add(insert_button);
default:
Label field_lbl = new Label();
field_lbl.ID = FieldName;
field_lbl.Text = String.Empty;
field_lbl.DataBinding += new EventHandler(OnDataBinding);
Container.Controls.Add(field_lbl);
break;
}
break;
case ListItemType.EditItem:
if (InfoType == "Button")
{
ImageButton update_button = new ImageButton();
update_button.ID = "update_button";
update_button.CommandName = "Update";
update_button.ImageUrl = "~/images/update.gif";
update_button.ToolTip = "Update";
update_button.OnClientClick =
"return confirm('Are you sure to update the record?')";
Container.Controls.Add(update_button);

// Similarly, add a button for Cancel

}
else
// if other key and non key fields then bind textboxes with texts
{
TextBox field_txtbox = new TextBox();
field_txtbox.ID = FieldName;
field_txtbox.Text = String.Empty;
// if to update then bind the textboxes with coressponding field texts
//otherwise for insert no need to bind it with text

if ((int)new Page().Session["InsertFlag"] == 0)
field_txtbox.DataBinding += new EventHandler(OnDataBinding);
Container.Controls.Add(field_txtbox);

}
break;
}
}When InfoType is not a Command it means we have to instantiate it with a label as in GridView's normal mode when each cell text of GridView's rows is displayed in label. Therefore, by default, control is instantiated with Label and is added into the Container. Since we have no more info types (other than command and string) then no further checks are required. We come to the outer check when ItemType is EditItem. Now, we need an inner check for info type (command or string). The template field will be instantiated in Button if the info type is Command; otherwise it requires TextBox for the cell text of edit item.

It is important to know that the CommandName of insert_button is set to "Edit" just to take advantage of the Edit mode that provides text boxes for all editable items. If the these text boxes are emptied, they can be used for insertion instead of editing without dedicating an extra row for it. This is easy and handy as it becomes a better approach when it is not known in advance how many columns there are in GridView's data source. I have taken a session variable InsertFlag that is set to 0 and 1 for Edit and Inert operations respectively.

Since we have to bind the labels in Item template and text boxes in EditItem template with corresponding cell values, the data binding event handler OnDataBinding of both label and text box populates the fields with cell values accordingly.

And you might also want to know how text boxes for each field get emptied when Insert button is clicked. The solution is simple; do not bind them with a database and apply a check while adding the data binding event handler of text box. Do not call OnDataBinding if the insert button is clicked.

Listing 5

if ((int)new Page().Session["InsertFlag"] == 0)
field_txtbox.DataBinding += new EventHandler(OnDataBinding);DataBinding Event Handler

The implementation of the data binding event handler "OnDataBindin"' is simple. First, we get the "bound_value_object" that is returned by the static method Eval of DataBinder class which takes two parameters. One is of type object called "data_item_container" (containing the DataItem that is assigned with sender control's NamingConatiner) and other is the string expression, FieldName. Once we get this bound_value_object, we assign its value (string) to the Text property of Label (if ItemType is Item; for normal mode) and TextBox (if ItemType is EditItem; for Edit mode).

Listing 6

private void OnDataBinding(object sender, EventArgs e)
{
object bound_value_obj = null;
Control ctrl = (Control)sender;
IDataItemContainer data_item_container =
(IDataItemContainer)ctrl.NamingContainer;
bound_value_obj = DataBinder.Eval(data_item_container.DataItem, FieldName);
switch (ItemType)
{
case ListItemType.Item:
Label field_ltrl = (Label)sender;
field_ltrl.Text = bound_value_obj.ToString();
break;
case ListItemType.EditItem:
TextBox field_txtbox = (TextBox)sender;
field_txtbox.Text = bound_value_obj.ToString();
break;
}
}The implementation of ITemplate is complete, although I want to mention that there are some event handlers, "insert_button_Click" and "edit_button_Click" for Insert and Edit buttons respectively. They do nothing except the former sets the Session[InsertFlag] to 1 and the later sets it to 0.

Some Interesting Codes

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


/// <summary>
/// Developer : Belbinson Toby
/// </summary>
namespace Class
{

public interface IEmployee
{
         void Result();
}

public interface IDeveloper
{
        void Result();
}

public class Employee
{
        public void Result()
       {
           Console.WriteLine("Employee");
       }
}


public class Developer : Employee, IEmployee, IDeveloper
{

              void IEmployee.Result()
              {
                     Console.WriteLine("IEmployee");
              }

             void IDeveloper.Result()
            {
                     Console.WriteLine("IDeveloper");
            }

            public new void Result()
           {
                   Console.WriteLine("Developer");
           }

}


public class Program
{
static void Main(string[] args)
{

Developer objDeveloper = new Developer();
objDeveloper.Result();// This will call Result Method in Developer Class

Employee objEmployee = new Developer();
objEmployee.Result();// This will call Result Method in Employee Class

IEmployee objIe = new Developer();
objIe.Result();// This will call Result Method in IEmployee Class

IDeveloper objId = new Developer();
objId.Result();// // This will call Result Method in IDeveloper Class

Console.ReadLine();

}
}
}

Extension Methods (C# Programming Guide)

http://msdn.microsoft.com/en-us/library/bb383977.aspx

Extension methods enable you to "add" methods to existing types without creating a new derived type, recompiling, or otherwise modifying the original type. Extension methods are a special kind of static method, but they are called as if they were instance methods on the extended type. For client code written in C# and Visual Basic, there is no apparent difference between calling an extension method and the methods that are actually defined in a type.




The most common extension methods are the LINQ standard query operators that add query functionality to the existing System.Collections.IEnumerable and System.Collections.Generic.IEnumerable<T> types. To use the standard query operators, first bring them into scope with a using System.Linq directive. Then any type that implements IEnumerable<T> appears to have instance methods such as GroupBy, OrderBy, Average, and so on. You can see these additional methods in IntelliSense statement completion when you type "dot" after an instance of an IEnumerable<T> type such as List<T> or Array.



The following example shows how to call the standard query operator OrderBy method on an array of integers. The expression in parentheses is a lambda expression. Many standard query operators take lambda expressions as parameters, but this is not a requirement for extension methods. For more information, see Lambda Expressions (C# Programming Guide).

Constraints on Type Parameters (C# Programming Guide)

http://msdn.microsoft.com/en-us/library/d5x73970(VS.80).aspx
When you define a generic class, you can apply restrictions to the kinds of types that client code can use for type arguments when it instantiates your class. If client code attempts to instantiate your class with a type that is not allowed by a constraint, the result is a compile-time error. These restrictions are called constraints. Constraints are specified using the where contextual keyword. The following table lists the six types of constraints: