Tuesday, January 15, 2008

asp.net 2.0 and up: DropDownList in GridView (using SQLDataSource)

To have a dropdownlist inside a gridview, we use the property "SelectedValue='<%# Eval("datakeyfield") %>' knowing that it won't show in the intellisense. To handle null values, we can have an item with a value of null. The SQLDataSource for the dropdownlist is better off put outside the gridview, so that it does not get created as many times as the dropdownlist is.

Here's the code for the DropDownList Template Field :
The Dropdownlist is Filled From a table called Categories (see schema below)

<asp:TemplateField HeaderText="Category" SortExpression="CategoryID">
<ItemTemplate>
<asp:DropDownList ID="DropDownList1" runat="server" DataSourceID="SourceCategories"
AppendDataBoundItems="true" DataTextField="CategoryName" DataValueField="CategoryID"
Width="190px" Enabled="false" SelectedValue='<%# Eval("CategoryID") %>'>
<asp:ListItem Text="No Item was Selected, to handle null values" Value="" />
</asp:DropDownList>
</ItemTemplate>
</asp:TemplateField>



In the code above, Notice the property SelectedValue, and the static Item to handle null values. to this, we add the AppendDataBoundItems Property, and the dropdownlist is ready.


Here's the complete code listing with a functional gridview:





The GridView is filled from a table Called Clients (see schema below)



<div>
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" CellPadding="4"
DataSourceID="SourceClients" ForeColor="#333333" GridLines="Both" Font-Names="Verdana"
Font-Size="10px" AllowSorting="true">
<Columns>
<asp:BoundField DataField="ClientID" HeaderText="ClientID" InsertVisible="False"
ReadOnly="True" SortExpression="ClientID" />
<asp:BoundField DataField="FullName" HeaderText="FullName" SortExpression="FullName" />
<asp:TemplateField HeaderText="Category" SortExpression="CategoryID">
<ItemTemplate>
<asp:DropDownList ID="DropDownList1" runat="server" DataSourceID="SourceCategories"
AppendDataBoundItems="true" DataTextField="CategoryName" DataValueField="CategoryID"
Width="190px" Enabled="false" SelectedValue='<%# Eval("CategoryID") %>'>
<asp:ListItem Text="No Item was Selected, to handle null values" Value="" />
</asp:DropDownList>
</ItemTemplate>
</asp:TemplateField>


</Columns>
</asp:GridView>
<asp:SqlDataSource ID="SourceClients" runat="server" ConnectionString="<%$ ConnectionStrings:ClientsConnectionString %>"
SelectCommand="SELECT * FROM [Clients]"></asp:SqlDataSource>
<asp:SqlDataSource ID="SourceCategories" runat="server" ConnectionString="<%$ ConnectionStrings:ClientsConnectionString %>"
SelectCommand="SELECT * FROM [Categories]"></asp:SqlDataSource>
</div>


Here's are the table definitions: (int and varchar(50) are the datatypes used)


image


Screen Shot for the gridview


image


Comments are welcome

Friday, January 11, 2008

asp.net 2.0 : Handling Null values for checkbox columns wihout loosing the Bind expression (works for GridView and FormView)

 

I looked for this for a while (the ability to keep Bind(""), not Eval("") and Also to be able to do the check for null outside the grid, and found this technique helpful:
        Put the checkbox control inside a user control, and handle the null values inside it. works like a charm.

Here's a link to the solution where I initially found it:

http://www.telerik.com/community/forums/thread/b311D-ctttt.aspx
look for the last 3 posts to this forum page (Fabian Schulz)

To go a little further, Here's the download for the source code of the CheckBox User Controls.
CheckBoxUserControl download

Here's a sample of what the code should look like :

The EditItemTemplate is missing, but can have the same code as the ItemTemplate, since the InvalidCastException is handled by checking for null values inside the checkbox user control.  (I will update this post with an EditItemTemplate).

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>

<%@ Register Src="DataEntryControls/CheckBoxControl.ascx" TagName="CheckBoxControl"
TagPrefix="uc1" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" CellPadding="4"
DataSourceID="SqlDataSource1" GridLines="None">
<Columns>
<asp:BoundField DataField="ClientID" HeaderText="ClientID" InsertVisible="False"
ReadOnly="True" SortExpression="ClientID" />
<asp:BoundField DataField="FullName" HeaderText="FullName" SortExpression="FullName" />
<asp:TemplateField HeaderText="IsValid">
<ItemTemplate>
<uc1:CheckBoxControl ID="CheckBoxControl1" runat="server" Checked='<%# Bind("IsValid") %>' />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</div>
<asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:ClientsConnectionString %>"
SelectCommand="SELECT * FROM [Clients]"></asp:SqlDataSource>
</form>
</body>
</html>

The ascx has no code behind but the page load.


As for the table, it's very simple. ClientID int auto, FullName varchar(50) and IsValid int or bit


Here's is the source code for the CheckBox Control :


CheckBoxControl.ascx:



<%@ Control Language="C#" AutoEventWireup="true" CodeFile="CheckBoxControl.ascx.cs" Inherits="Controls_DataEntryControls_CheckBoxControl" %>
<asp:CheckBox ID="CheckBox1" runat="server" />



CheckBoxControl.ascx.cs




using System;
public partial class Controls_DataEntryControls_CheckBoxControl : System.Web.UI.UserControl
{
private bool m_checked = false;
protected void Page_Load(object sender, EventArgs e)
{
m_checked = CheckBox1.Checked;
}
public object Checked
{
get { return m_checked; }
set
{
if (value.GetType() == DBNull.Value.GetType()) m_checked = false;
else if (value == null) m_checked = false;
else if (value.GetType() == typeof(bool)) m_checked = (bool)value;
else m_checked = false;
}
}
protected void Page_PreRender()
{
CheckBox1.Checked = m_checked;
}
}

Comments are welcome


This technique is based on the fact that handling null values is the concern of the control itself, not the gridview of formview, since the control forces a specific data type for its property. I beleive we could say that this is a good application of the seperation of concern pattern in asp.net.

Saturday, January 05, 2008

asp.net 2.0 : TextBox User Control with TextChanged Event (Event Bubbling from user controls)

including a textbox in a user control can save a lot of messy code in a form, as well as encapsulate validation and other functionalities (such as ajax calendar functionality). A small challenge though, it's bubbling the textchanged event from the TextBox to the top

Here's a link to a sample website with an aspx page and the TextBox user control in it :

>> TextBox Changed Event in a user control sample

Code :

TextBox User Control :

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="TextBox.ascx.cs" Inherits="Controls_ReferenceData_ChiffresTextBox" %>
<asp:TextBox ID="TextBox1" runat="server" CssClass="champ" /><br />
<asp:RequiredFieldValidator ID="RequeiredFieldValidator1" runat="server" ControlToValidate="TextBox1"
ErrorMessage="This Field is Required" Display="Dynamic" />



Code Behind :




using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public partial class Controls_ReferenceData_ChiffresTextBox : System.Web.UI.UserControl
{
protected void Page_Load(object sender, EventArgs e)
{

}

public string Text
{
get { return this.TextBox1.Text; }
set { this.TextBox1.Text = value; }
}

public bool AutoPostBack
{
get { return TextBox1.AutoPostBack; }
set { TextBox1.AutoPostBack = value; }
}

#region "Other properties"
public bool EnabledRfv
{
get { return this.RequeiredFieldValidator1.Enabled; }
set { this.RequeiredFieldValidator1.Enabled = value; }
}


#endregion

protected override void OnInit(EventArgs e)
{
this.TextBox1.TextChanged += new EventHandler(TextBox1_TextChanged);
base.OnInit(e);
}

void TextBox1_TextChanged(object sender, EventArgs e)
{
OnBubbleTextChanged(e);
}

public event EventHandler BubbleTextChanged;

protected void OnBubbleTextChanged(EventArgs e)
{
if (BubbleTextChanged != null)
BubbleTextChanged(this, e);

}


}



 



For Implementation in an aspx page, here's what the code looks like:



Register tag




<%@ Register Src="Controls/DataEntryControls/TextBox.ascx" TagName="TextBox" TagPrefix="uc1" %>



 


Control's tag



<uc1:TextBox ID="TextBox1" runat="server" AutoPostBack="true" OnBubbleTextChanged="OnTextChanged" />



 



Code Behind




using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public partial class TextBoxWithTextChange : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{

}
protected void OnTextChanged(object sender, EventArgs e)
{
Response.Write(this.TextBox1.Text);
}

}



in the code behind, we create the method OnTextChanged to handle the event. This sample I picked out from a blog, and added the possiblity to add properties. Sadly, I search and can't find it easily, so I prefered to post something similar, for more search results regarding the textchanged event bubbling from a user conrol subject.



The TextChanged event does not show in the list of events for the user control. something to think about, otherwise, this technique makes it easy to develop such a functionality.



Comments are welcome.

A User Interface Data Binding Overview in asp.net

Granularity (one field, one control) :

A definition of databing could be having a link between the field in the datasource and a control.

When we talk about data binding, the first thing that should come to mind, is that we are binding fields to controls. In more detail, when we use a GridView to bind it to a table, in fact we are binding each field in the database to a specific control, present in the form of a collection, which makes us say, we are binding a table to the grid, while the granular aspect of it is that we are binding many fields to many controls.

Binding Scripting Syntax for Grids, Datalists, Formviews and detailviews:

Two way binding (very popular)

<%
   1: # Bind("fieldname") 
%>



One way Binding (ReadOnly)




<%
   1: # Eval("fieldname") 
%>


Another one is :


<%
   1: # DataBinder.Eval(Container.DataItem, "fieldname") 
%>



 



This are helper Functions. Here's how they work :



when we have a textbox inside a TemplateField, in a Gridview : We have the following Syntax :




<TemplateField>
<EditItemTemplate>
<asp:TextBox id="txtName" runat="server" Text='<%# Bind("Name") %>' />
</EditItemTemplate>
</TemplateField>



In fact, The Bind Method is executed during the ItemDataBound Event (one popular event in the 1.1 DataGrid control used to initilize child controls in a GridView). The Bind method helps not having to write code behind syntax to bind each field during insert and update.


 


Best Practices using the SqlDataSource Control :


If we notice, using SQLDataSource, (note : thanks Adnane for the tip), there's a property named DataSourceMode :


This property is really great, since it gives us DataSet Mode and DataReader Mode. DataSet Mode is set by default, nice, that way The paging and sorting can work by default.


 


image


 


When to change the DataSourceMode property:


For better use, there' no need in using the default mode to fill a DropDownList or a ListBox, instead we choose DataReader Mode, which will be of course more efficient.


 


For differences between DataReader and DataSet, please take a look at a previous post (DataSet vs DataReader). this post includes links to msdn explaining the difference, as well as giving a breif overview of the difference.


 


Comments are welcome