Friday, October 17, 2008

DOCTYPE element, why do we need it ?

Hey guys !


I wanna share with you some things about this DOCTYPE element which is included at the top of the html page.


Firstly, if we are using the Microsoft's AJAX Toolkit, we should ensure that we have a DOCTYPE element included, because some of our controls can freeze and not work. In my case, I was using a ModalPopupExtender which appeared in the upper left corner of the window and everything freezes (for comparision it's expected to be showed in the center of the screen ). For bad, browsers are different and in Firefox this ModalPopupExtender will work without problems, but there's no chance to work in IE. So if something with your AJAX Toolkit is behaving strange the first thing to check is the DOCTYPE element :)


Another thing which is notable to not work when the DOCTYPE element is missing is the CSS. Some properties like font-size can stop working, or again behave strange .. what is more it will depend on the browser, some things will work on Firefox and won't work in IE .. so it becomes even harder to locate the problem.


To conclude, if you have strange problems with AjaxToolkit or CSS, firstly ensure to check whether there is a DOCTYPE element in the html. Yes, I know that when Visual Studio creates a page it includes a DOCTYPE element, but in my case someone has removed this DOCTYPE for some reason .. and I had hard times figuring out why the ajaxcontrol toolkit controls was acting so strange.


More information about the doctype and the browser modes:
http://en.wikipedia.org/wiki/Quirks_mode -- quirks mode is the mode the browser enters, when you don't specify a DOCTYPE in all the browsers, when we're talking about the Transitional DTD. (You can check this by looking up in the table for HTML 4.01 spec. and Transitional DTD)

Thursday, August 14, 2008

Persisting dynamically built GridView's state and data

As I promised, there will be one more post about creating dynamically a GridView.
Let’s now see what happens on a Post Back ?
Our GridView created dynamically with template fields is lost. As we know the GridView has a property called “EnableViewState”. If we set this property to “true” we can expect our GridView and it’s data to be persisted after the post back. But that’s not the case. The “EnableViewState” itself saves only the data in the cells of the GridView to the ViewState, so we will again see nothing. What we have to do (something we should do to every control we have somehow constructed dynamically) is to build the GridView over and over again every time the Page is sent back to the server. We have to do this on an event where we still have the ability to change the Page’s layout and controls included in it.
For example if we are creating an UserControl we should reconstruct the GridView on it’s Init event ( http://msdn.microsoft.com/en-us/library/system.web.ui.control.init.aspx ). If we are doing this in a Web Page we should place our code in the PreInit event ( http://msdn.microsoft.com/en-us/library/system.web.ui.page.preinit.aspx ).
Now we have accomplished our task to save the GridView after Post Back. Unfortunately, creating dynamically controls needs much more coding, than creating them statically.
The other thing I would like to share is very simple. It answers the question ‘How do we handle the edit of such a custom grid ?’
We will create our own column with Edit/Update/Cancel link buttons. We place a code like this in the GridView control:
<asp:TemplateField ShowHeader="False">
<ItemTemplate>
<asp:LinkButton ID="lbEdit" CommandName="Edit" Text="Edit" runat="server" />

</ItemTemplate>
<EditItemTemplate>
<asp:LinkButton ID="lbUpdate" CommandName="Update" Text="Update" runat="server" />

<asp:LinkButton ID="lbCancel" CommandName="Cancel" Text="Cancel" runat="server" />

</EditItemTemplate>
</asp:TemplateField>

Please, note that we could have just set the property of the GridView “AutoGenerateEditButton” to true to let the framework generate such a column for us.
No we have to handle the events for Update, Cancel, Edit adding code again in the GridView for the events, like this:
OnRowEditing="gv_RowEditing"
OnRowCancelingEdit="gv_RowCancelingEdit"
OnRowUpdating="gv_RowUpdating"


Now the only thing left is to implement the above methods in the code behind to handle the raised events. Sample code goes below:
protected void gv_RowEditing(object sender, GridViewEditEventArgs e)
{
gv.EditIndex = e.NewEditIndex; // set the edit index, which causes
// the GridView to enter it’s edit
// mode
// Rebind data here

}
protected void gv_RowCancelingEdit(object sender, GridViewCancelEditEventArgs e)
{
gv.EditIndex = -1; // Clear the edit index, and return
// to change the mode again.
// Rebind data here

}
protected void gv_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
DataTable dt = TableGV; // This is my object behind the
// GridView which holds it’s data.
// And I want it updated.

GridViewRow row = gv.Rows[e.RowIndex];
for (int i = 0; i < dt.Columns.Count; i++)
{
dt.Rows[gv.EditIndex][i] = ((TextBox)(row.Cells[i + 1].Controls[0])).Text.Trim(); // Get the data from the GridViewRow
}
gv.EditIndex = -1; // Again change the mode
// Rebind data here

}

That’s all, we now have a complete editable custom dynamically created GridView Control.

Thursday, July 24, 2008

How to build a Grid View dynamically ?

Today I will show you something pretty standard - how to build a asp:GridView when you don't know in advance how it will be formatted, what Columns should be bounded...
We have to build the GridView’s structure – it’s Columns. We can see that GridView.Columns.Add method takes a DataControlField as a parameter, so our attention should go to Controls inheriting DataControlField so that we can add them to the Columns collection.

There are two kinds of columns we can use - a BoundField and a TemplateField.

The first one – a BoundField , is easy to create and use. We can set properties like DataField,HeaderText, HeaderStyle, ReadOnly and so on. But we can’t set a template. This control should be used when adding a very simple row, which won’t be edited or no complex formatting will be applied to it. It’s the easiest way to add a new column, but it’s not flexible enough for all we can need. So, BoundField should be used when we don’t want anything complex from the Column.

The TemplateField on the other hand is powerful.

namespace System.Web.UI.WebControls
{
public class TemplateField : DataControlField
{
public TemplateField();

public virtual ITemplate AlternatingItemTemplate { get; set; }
public virtual bool ConvertEmptyStringToNull { get; set; }
public virtual ITemplate EditItemTemplate { get; set; }
public virtual ITemplate FooterTemplate { get; set; }
public virtual ITemplate HeaderTemplate { get; set; }
public virtual ITemplate InsertItemTemplate { get; set; }
public virtual ITemplate ItemTemplate { get; set; }
protected override DataControlField CreateField();
public override void ExtractValuesFromCell(IOrderedDictionary dictionary, DataControlFieldCell cell, DataControlRowState rowState, bool includeReadOnly);
public override void InitializeCell(DataControlFieldCell cell, DataControlCellType cellType, DataControlRowState rowState, int rowIndex);
public override void ValidateSupportsCallback();
}
}

We can see from it’s class that it contains Properties for all the possible Templates (EditItemTemplate, ItemTemplate, InsertItemTemplate and etc.) . All templates should implement the ITemplate Interface , which is simple enough – it contains only one method – InstantiateIn(Control container)

namespace System.Web.UI
{
public interface ITemplate
{
void InstantiateIn(Control container);
}
}

In this method we should add whatever we like in the container. This method is called for every cell of the GridView, so the container is actually a DataControlField (which is not so important for now, except the fact that should be noted – the DataControlField is not the NamingContainer, but the GridViewRow is).
Now, for example , let’s create a class for ItemTemplate. Here is a sample code for an ItemTemplate:
public class CustomTemplateField : ITemplate
{
public CustomTemplateField()
{
}

public void InstantiateIn(Control container)
{
Label label = new Label();
label.DataBinding += new EventHandler(label_DataBinding); // use the DataBinding event to
// set the data to the label

container.Controls.Add(label); // Simply add the control to the Controls
// collection of the container

}

void label_DataBinding(object sender, EventArgs e)
{
Label lbl = sender as Label; // Get the label
GridViewRow gvr = lbl.NamingContainer as GridViewRow; // And get it's naming container
string text = DataBinder.Eval(gvr.DataItem, "Name").ToString(); // We can now use the DataItem
// to bind some data to our
// Controls in the cell

lbl.Text = text; // we can of course here perform some formatting
}
}

Any other Template’s implementation is similar to the above’s one. If we want to provide edit functionality, we should make an EditItemTemplate, for example like this one:
public class EditItemTemplate : ITemplate
{
public EditItemTemplate()
{
}

public void InstantiateIn(Control container)
{
TextBox txt = new TextBox();
txt.ID = "TextBoxID";
txt.DataBinding += new EventHandler(txt_DataBinding);
}

void txt_DataBinding(object sender, EventArgs e)
{
TextBox tb = sender as TextBox;
GridViewRow gvr = sender as GridViewRow;
tb.Text = DataBinder.Eval(gvr.DataItem, "Name").ToString();
}
}

So it’s pretty easy to create dynamically a GridView with TemplateFields. And that’s all we needed to build dynamically a GridView !

What's next ?
In the next post, I will show you how we can handle the edit operation on such GridView and how to use it's ViewState.