Databinding on Composite Control

S

Steve

I'm trying to implement databinding on a composite control and I'm getting an
error with the data when I change the DataSource. The first time I set the
DataSource and call DataBind() everything works fine, but when I set the
DataSource to a new value (DataTable) and then call DataBind again, I get
some strange results from the command events of some embedded ImageButton
controls... althought the data appears to be displayed correctly, the
CommandName and CommandArguement values are offset by 1 row. What's worse,
is the error goes away after I post-back a few times (which restores the data
from the ViewState). This is driving me nuts. It seems like the error is
somehow related to the order of operations surrounding the post-back,
EnsureChildControls (in OnLoad), and then calling DataBind (which creates the
controls again).

I'm attaching the full class, if anyone is willing to be of service of give
it a look. I would appreciate any help greatly.


//class code start here:

using System;
using System.Data;
using System.Collections;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;


namespace System.Web.UI.WebControls
{
/// <summary>
/// Summary description for ItemList.
/// </summary>
[DefaultProperty("Text"),
ToolboxData("<{0}:ItemList runat=server></{0}:ItemList>")]
public class ItemList : System.Web.UI.WebControls.WebControl
{
private bool _isGrid = true;
private DataTable _dataTable = null;


#region public properties/methods/overrides
public ItemList() : base(){}


protected override void OnLoad(EventArgs e)
{
base.OnLoad (e);
if( this.Page.IsPostBack )
{
EnsureChildControls();
}
}


public bool RenderGrid
{
get
{
return _isGrid;
}
set
{
_isGrid = value;
}
}


override public object DataSource
{
set
{
_dataTable = (DataTable)value;
ViewState["data"] = value;
}
}


public override void DataBind()
{
CreateControlHierarchy();
}


protected override void CreateChildControls()
{
CreateControlHierarchy();
}


private void CreateControlHierarchy()
{
Controls.Clear();
ClearChildViewState();
if( !IsTrackingViewState ){ TrackViewState(); }

if( _isGrid )
{
if( _dataTable == null )
{
CreateItemGrid( (DataTable)ViewState["data"] );
}
else
{
CreateItemGrid( _dataTable );
}
}
else
{
}

ChildControlsCreated = true;
}
#endregion



#region CreateItemGrid
private void CreateItemGrid(DataTable dt)
{

Table t = new Table();
t.CssClass = "reportTable";

TableRow r = new TableRow();
TableCell cl = new TableCell();

r = new TableRow();
int c = 1;
for( ; c<dt.Columns.Count; c++ )
{
r.Cells.Add( AddGridHdrFtrCell( dt.Columns[c].ColumnName, true ) );
}
r.Cells.Add( AddGridHdrFtrCell( " ", true ) );
r.Cells.Add( AddGridHdrFtrCell( " ", true ) );
t.Rows.Add( r );

for( int row=0; row<dt.Rows.Count; row++ )
{
r = new TableRow();
c = 1;
for( ; c<dt.Columns.Count; c++ )
{
r.Cells.Add( AddGridDataCell(
dt.Rows[row][dt.Columns[c].ColumnName].ToString(), row ) );
}
r.Cells.Add( AddGridLinkButtonCell( dt.Rows[row]["itmPk"].ToString(),
true, row) );
r.Cells.Add( AddGridLinkButtonCell( dt.Rows[row]["itmPk"].ToString(),
false, row) );
t.Rows.Add( r );
}

r = new TableRow();
cl = new TableCell();
cl.ColumnSpan = dt.Columns.Count + 2;
cl.Text = string.Format( "{0} items", dt.Rows.Count );
cl.CssClass = "reportFooter";
r.Cells.Add( cl );
t.Rows.Add( r );

r = new TableRow();
cl = new TableCell();
cl.ColumnSpan = dt.Columns.Count + 2;
cl.Text = " ";
cl.CssClass = "reportItem";
r.Cells.Add( cl );
t.Rows.Add( r );


this.Controls.Add( t );
}


private TableCell AddGridHdrFtrCell(string text, bool hdr)
{
TableCell c = new TableCell();
c.Text = text;
c.CssClass = hdr ? "reportHeader" : "reportFooter";
return c;
}


private TableCell AddGridDataCell(string text, int i)
{
TableCell c = new TableCell();
c.Text = text;
c.CssClass = (i+1)%2==0 ? "reportItem" : "reportAltItem";
return c;
}


private TableCell AddGridLinkButtonCell(string pk, bool view, int i)
{
ImageButton l = new ImageButton();
l.Visible = visible;
l.CommandArgument = pk;
//l.Command += new CommandEventHandler(ImageButton_Command);

if( view )
{
l.ImageUrl = "../images/rec_view.gif";
l.AlternateText = "View detail " + pk;
l.CommandName = "view";
}
else
{
l.ImageUrl = "../images/rec_edit.gif";
l.AlternateText = "Edit this item " + pk;
l.CommandName = "edit";
}

TableCell c = new TableCell();
c.Controls.Add( l );
c.CssClass = (i+1)%2==0 ? "reportItem" : "reportAltItem";
return c;
}


protected override bool OnBubbleEvent(object source, EventArgs ea)
{
bool handled = false;
if( ea is CommandEventArgs )
{
CommandEventArgs e = (CommandEventArgs)ea;

switch( e.CommandName.ToLower() )
{
case "view":
{
OnRecordAction( new RecordActionEventArgs(
e.CommandArgument.ToString(), RecordMode.Select ) );
handled = true;
break;
}
case "edit":
{
OnRecordAction( new RecordActionEventArgs(
e.CommandArgument.ToString(), RecordMode.Update ) );
handled = true;
break;
}
}

}

return handled;
}



private void ImageButton_Command(object sender, CommandEventArgs e)
{
}
#endregion

}
}
 
T

Teemu Keiski

Hi,

do not store the DataTable to ViewState.

the sequence of things should be like this

protected override void CreateChildControls()
{
Controls.Clear();
if(ViewState["RowCount"] != null)
{
CreateControlHierarchy(false);
}

}



public override void DataBind()
{
base.OnDataBinding(EventArgs.Empty);
Controls.Clear();
ClearChildViewState();
TrackViewState();
CreateControlHierarchy(true);
ChildControlsCreated = true;
}

protected virtual void CreateControlHierarchy(bool usedatasource)
{
//...
}

CreateControlHierarchy takes in boolean value to indicate if it's
databinding or not (if there is data source or not). If there is(true), it
loops through the data source and creates controls plus stores information
needed to recreate them to ViewState (in this sample RowCount, if columns
vary then also ColumnCount etc etc). In case when its false, it just
recreates the control instances based on the counts stored to ViewState
(therefore it doesn't need to DataTable instance, which would just blow the
view state of the page)

--
Teemu Keiski
ASP.NET MVP, AspInsider
Finland, EU
http://blogs.aspadvice.com/joteke

Steve said:
I'm trying to implement databinding on a composite control and I'm getting
an
error with the data when I change the DataSource. The first time I set
the
DataSource and call DataBind() everything works fine, but when I set the
DataSource to a new value (DataTable) and then call DataBind again, I get
some strange results from the command events of some embedded ImageButton
controls... althought the data appears to be displayed correctly, the
CommandName and CommandArguement values are offset by 1 row. What's
worse,
is the error goes away after I post-back a few times (which restores the
data
from the ViewState). This is driving me nuts. It seems like the error is
somehow related to the order of operations surrounding the post-back,
EnsureChildControls (in OnLoad), and then calling DataBind (which creates
the
controls again).

I'm attaching the full class, if anyone is willing to be of service of
give
it a look. I would appreciate any help greatly.


//class code start here:

using System;
using System.Data;
using System.Collections;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;


namespace System.Web.UI.WebControls
{
/// <summary>
/// Summary description for ItemList.
/// </summary>
[DefaultProperty("Text"),
ToolboxData("<{0}:ItemList runat=server></{0}:ItemList>")]
public class ItemList : System.Web.UI.WebControls.WebControl
{
private bool _isGrid = true;
private DataTable _dataTable = null;


#region public properties/methods/overrides
public ItemList() : base(){}


protected override void OnLoad(EventArgs e)
{
base.OnLoad (e);
if( this.Page.IsPostBack )
{
EnsureChildControls();
}
}


public bool RenderGrid
{
get
{
return _isGrid;
}
set
{
_isGrid = value;
}
}


override public object DataSource
{
set
{
_dataTable = (DataTable)value;
ViewState["data"] = value;
}
}


public override void DataBind()
{
CreateControlHierarchy();
}


protected override void CreateChildControls()
{
CreateControlHierarchy();
}


private void CreateControlHierarchy()
{
Controls.Clear();
ClearChildViewState();
if( !IsTrackingViewState ){ TrackViewState(); }

if( _isGrid )
{
if( _dataTable == null )
{
CreateItemGrid( (DataTable)ViewState["data"] );
}
else
{
CreateItemGrid( _dataTable );
}
}
else
{
}

ChildControlsCreated = true;
}
#endregion



#region CreateItemGrid
private void CreateItemGrid(DataTable dt)
{

Table t = new Table();
t.CssClass = "reportTable";

TableRow r = new TableRow();
TableCell cl = new TableCell();

r = new TableRow();
int c = 1;
for( ; c<dt.Columns.Count; c++ )
{
r.Cells.Add( AddGridHdrFtrCell( dt.Columns[c].ColumnName, true ) );
}
r.Cells.Add( AddGridHdrFtrCell( " ", true ) );
r.Cells.Add( AddGridHdrFtrCell( " ", true ) );
t.Rows.Add( r );

for( int row=0; row<dt.Rows.Count; row++ )
{
r = new TableRow();
c = 1;
for( ; c<dt.Columns.Count; c++ )
{
r.Cells.Add( AddGridDataCell(
dt.Rows[row][dt.Columns[c].ColumnName].ToString(), row ) );
}
r.Cells.Add( AddGridLinkButtonCell( dt.Rows[row]["itmPk"].ToString(),
true, row) );
r.Cells.Add( AddGridLinkButtonCell( dt.Rows[row]["itmPk"].ToString(),
false, row) );
t.Rows.Add( r );
}

r = new TableRow();
cl = new TableCell();
cl.ColumnSpan = dt.Columns.Count + 2;
cl.Text = string.Format( "{0} items", dt.Rows.Count );
cl.CssClass = "reportFooter";
r.Cells.Add( cl );
t.Rows.Add( r );

r = new TableRow();
cl = new TableCell();
cl.ColumnSpan = dt.Columns.Count + 2;
cl.Text = " ";
cl.CssClass = "reportItem";
r.Cells.Add( cl );
t.Rows.Add( r );


this.Controls.Add( t );
}


private TableCell AddGridHdrFtrCell(string text, bool hdr)
{
TableCell c = new TableCell();
c.Text = text;
c.CssClass = hdr ? "reportHeader" : "reportFooter";
return c;
}


private TableCell AddGridDataCell(string text, int i)
{
TableCell c = new TableCell();
c.Text = text;
c.CssClass = (i+1)%2==0 ? "reportItem" : "reportAltItem";
return c;
}


private TableCell AddGridLinkButtonCell(string pk, bool view, int i)
{
ImageButton l = new ImageButton();
l.Visible = visible;
l.CommandArgument = pk;
//l.Command += new CommandEventHandler(ImageButton_Command);

if( view )
{
l.ImageUrl = "../images/rec_view.gif";
l.AlternateText = "View detail " + pk;
l.CommandName = "view";
}
else
{
l.ImageUrl = "../images/rec_edit.gif";
l.AlternateText = "Edit this item " + pk;
l.CommandName = "edit";
}

TableCell c = new TableCell();
c.Controls.Add( l );
c.CssClass = (i+1)%2==0 ? "reportItem" : "reportAltItem";
return c;
}


protected override bool OnBubbleEvent(object source, EventArgs ea)
{
bool handled = false;
if( ea is CommandEventArgs )
{
CommandEventArgs e = (CommandEventArgs)ea;

switch( e.CommandName.ToLower() )
{
case "view":
{
OnRecordAction( new RecordActionEventArgs(
e.CommandArgument.ToString(), RecordMode.Select ) );
handled = true;
break;
}
case "edit":
{
OnRecordAction( new RecordActionEventArgs(
e.CommandArgument.ToString(), RecordMode.Update ) );
handled = true;
break;
}
}

}

return handled;
}



private void ImageButton_Command(object sender, CommandEventArgs e)
{
}
#endregion

}
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,768
Messages
2,569,575
Members
45,053
Latest member
billing-software

Latest Threads

Top