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.

18 comments:

Anonymous said...

I don't get a Text property on the user control.

oudinia said...

Hello there,
I did not add a text property to the user control, you can add it with the following code:
public string Text
{
get {return this.CheckBox1.Text;}
set {this.CheckBox1.Text = value;}
}

Regards

Anonymous said...

very helpful. A simple question - now that I have swapped in your control, I can't access the checkbox in codebehind anymore. this is what I was using

protected void RadGrid1_Update(object source, Telerik.Web.UI.GridCommandEventArgs e)
{
CheckBox cbIsSecured = edititem.FindControl("cbIsSecured") as CheckBox ;
int isSecured = 0;
if (cbIsSecured.Checked)
{
isSecured = 1;
}
}

... I get this error now:

Object reference not set to an instance of an object.

Anonymous said...

I also get the 'object reference not set' error in the Page_Load and im wondering how this works for anyone. To the blogger - do you ever respond to the comments or should i look elsewhere?

Anonymous said...

For the benefit of all others, the reason for my error was not registering the control in the page header. I had assumed that by registering the control in the web.config assembly section it would be available everywhere, but this only loads the assembly, not the usercontrol itself and hence not the controls in the usercontrol. That fixed everything

Anonymous said...

Also here is a more simplified version of the UC (markup the same):

public partial class BoundCheckBox : UserControl
{
public object Checked
{
get
{
return this.checkBox.Checked;
}

set
{
if (value is bool)
{
this.checkBox.Checked = (bool) value;
}
else
{
this.checkBox.Checked = false;
}
}
}
}

oudinia said...

Hello Everyone,

First it's great to see how everyone is commenting this post. I'm sorry for not responding promptly, Yesterday, My only uncle (my father's brother) passed away, which does not give much time to blog.
thanks everyone for trusting my code on this post

Anonymous said...

My Solution:

namespace Softex.Web.Utils
{
public class CheckBox : System.Web.UI.WebControls.CheckBox
{
public new Boolean? Checked
{
get
{
return base.Checked;
}
set
{
if (value == null)
base.Checked = false;
else
base.Checked = (Boolean)value;
}
}
}
}

greeting Eric
(Sorry for your uncle)

oudinia said...

thanks Eric for enriching this post. It's one of my favorite issues :)

I'll definitely try your method too.

for my uncle, it's all our destiny, the day will come.

the least we can do before then, is to create a postive atmosphere, sharing knowledge and experience for a good cause.

Anonymous said...
This comment has been removed by a blog administrator.
Anonymous said...
This comment has been removed by a blog administrator.
Anonymous said...
This comment has been removed by a blog administrator.
rtpHarry said...

Great article - saved me. After about an hour of searching I found this and it worked for my requirements. Pretty simple when you think about it but still cool.

To the people that try to search for CheckBox afterwards - it doesnt exist anymore as its now a Controls_DataEntryControls_CheckBoxControl control.

r4i said...

That code was just fantastic......Thanx for the valuable information. This was just the thing I was looking for, keep posting. Will be visiting back soon.

Juba said...

Hello all!

I tried using the control but I'm getting an error of 'object reference not set' and it is tagged to my aspx page (I dragged and dropped it there) and it is visible but when I run my ViewGrid and try to access it it crashes.
According to Xca][ibur's posting he "...had assumed that by registering the control in the web.config assembly section " - is it necessary and how to do it? I thought that using Web User Controls were straight forward!
Thanks for any feedback!

oudinia said...

Hello Juba,
I'll be coming back with more really soon. For this one, I will repost a complete code again, as I had issues regarding hosting, and so many changes.

I have created a new blog in parallel, http://oudinia.wordpress.com
still trying to figure out a way to bring life back to this blog :)
more 3.5 and 4.0 really soon

No need to register anything.
Could anyone send me a working version, modified, of this code. that would be so nice. otherwise, I will still recreated the sample.

Thanks everyone for your trust in the code posted here, you make blogging fun

Zany said...

Thanks oudinia!

The null really got me crazy for a few hours.

Anonymous said...

10 years later, still works like a charm. Thanks!