Databinding on Composite Control

Discussion in 'ASP .Net Building Controls' started by Steve, Dec 15, 2005.

  1. Steve

    Steve Guest

    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

    }
    }
     
    Steve, Dec 15, 2005
    #1
    1. Advertising

  2. Steve

    Teemu Keiski Guest

    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" <> wrote in message
    news:...
    > 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
    >
    > }
    > }
     
    Teemu Keiski, Dec 18, 2005
    #2
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. sleigh
    Replies:
    1
    Views:
    2,720
    sleigh
    Feb 12, 2004
  2. Charlie@CBFC
    Replies:
    1
    Views:
    539
    Teemu Keiski
    Oct 9, 2005
  3. =?Utf-8?B?U3RldmU=?=

    Databinding on Composite Control

    =?Utf-8?B?U3RldmU=?=, Dec 15, 2005, in forum: ASP .Net
    Replies:
    0
    Views:
    574
    =?Utf-8?B?U3RldmU=?=
    Dec 15, 2005
  4. Chad
    Replies:
    0
    Views:
    241
  5. Steve

    Databinding on Composite Control

    Steve, Dec 15, 2005, in forum: ASP .Net Web Controls
    Replies:
    0
    Views:
    115
    Steve
    Dec 15, 2005
Loading...

Share This Page