Dynamically added Templated Columns (Implementing ITemplate) in DataGrid - How do I wire up events?

Discussion in 'ASP .Net Datagrid Control' started by David, Feb 13, 2004.

  1. David

    David Guest

    Hi,

    I have a VB.NET / ASP.NET program I'm trying to debug in which the columns in the DataGrid change depending on user selections. The data is sourced from a database, so the number of rows varies with the selection parameters. The columns are being added dynamically at runtime. There are 4 columns that are templated columns implementing the ITemplate interface. These columns are TextBoxes in which I want to be able to handle the TextChanged event. (No Edit / Update button on the grid, just a blank TextBox that should raise the TextChanged event when it loses focus.)

    I have enabled AutoPostback, as well as ViewState. However, the TextChanged event is never fired. After researching a bit on the internet, it appears as if it won't be fired because the control doesn't exist on the Page_Load event. I've seen numerous examples of how to deal with dynamically created controls on a WebForm, and numerous questions on how to do this in a DataGrid, but no explicit answers on how to accomplish it.

    Any suggestions (especially code examples!) would be greatly appreciated!

    Thanks!
    David
    David, Feb 13, 2004
    #1
    1. Advertising

  2. Hi David,

    Thank you for posting in the community!

    Based on my understanding, your column implement the ITemplate interface,
    which contains TextBox. Then you dynamicly add this column into the
    datagrid control. But the TextBox's changed event does not fire.

    =================================================
    Can you paste some code snippet to reproduce out your issue?

    Actually, I have writen a sample project for you like this:

    Dim ds As DataSet
    Private Sub Page_Load(ByVal sender As System.Object, ByVal e As
    System.EventArgs) Handles MyBase.Load
    Dim tc As TemplateColumn = New TemplateColumn
    Dim tbc As TextBoxColumn = New TextBoxColumn
    tc.ItemTemplate = tbc
    DataGrid1.Columns.Add(tc)

    getsource()
    dodatabinding()
    End Sub

    Private Sub getsource()
    Dim adapter As SqlDataAdapter = New SqlDataAdapter("select * from
    jobs", "server=localhost;database=pubs;uid=sa;pwd=")
    ds = New DataSet
    adapter.Fill(ds)
    End Sub

    Private Sub dodatabinding()
    DataGrid1.DataSource = ds
    DataGrid1.DataBind()
    End Sub

    Public Class TextBoxColumn
    Implements ITemplate

    Public Sub InstantiateIn(ByVal container As System.Web.UI.Control)
    Implements System.Web.UI.ITemplate.InstantiateIn
    Dim tb As TextBox = New TextBox
    tb.AutoPostBack = True
    tb.ID = "tb"
    AddHandler tb.TextChanged, AddressOf TextChangedHandler
    container.Controls.Add(tb)
    End Sub

    Private Sub TextChangedHandler(ByVal sender As Object, ByVal e As
    EventArgs)
    CType(sender, TextBox).Page.Response.Write("TextChangedHandler")
    End Sub
    End Class

    This works well.
    Note: I use the SqlServer's default "jobs" table in "pubs" database.

    =============================================================
    Please apply my suggestion above and let me know if it helps resolve your
    problem.

    Thank you for your patience and cooperation. If you have any questions or
    concerns, please feel free to post it in the group. I am standing by to be
    of assistance.
    Have a nice day!!

    Best regards,
    Jeffrey Tan
    Microsoft Online Partner Support
    Get Secure! - www.microsoft.com/security
    This posting is provided "as is" with no warranties and confers no rights.
    Jeffrey Tan[MSFT], Feb 16, 2004
    #2
    1. Advertising

  3. David

    David Guest

    Hi Jeffrey

    I'm doing something a bit different in my program where I dynamically determine what columns are to be displayed (user selectable). I'm going to try your example to see if I can make it work. If not, I'll come up with a sample of my own to better illustrate what I'm trying to do in my code

    Thanks
    David
    David, Feb 17, 2004
    #3
  4. David

    David Guest

    Hi Jeffrey

    Here's an example of what I'm trying to do in my program. I stripped out most of the functionality so I could just test the events on the dynamically generated TextBox. I think all you have to do to recreate this is create a new WebForm, add a DataGrid to it (DataGrid1), set the AutoGenerateColumns property for the DataGrid to False, cut / paste this code into the code-behind page, and try it out

    I'm using the Sales table in the Pubs database. You will need to go and set a few of the "qty" fields to 0 to see the textbox show up in the rendered page

    I'd appreciate any comments / suggestions you have

    Thanks
    Davi

    ********* Code Below ************

    Imports System.Data.SqlClien

    Public Class WebForm
    Inherits System.Web.UI.Pag

    Dim CONN_STR As String = "server=localhost;Integrated Security=SSPI;Initial Catalog=pubs

    #Region " Web Form Designer Generated Code

    'This call is required by the Web Form Designer
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent(

    End Su
    Protected WithEvents DataGrid1 As System.Web.UI.WebControls.DataGri

    'NOTE: The following placeholder declaration is required by the Web Form Designer
    'Do not delete or move it
    Private designerPlaceholderDeclaration As System.Objec

    Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Ini
    'CODEGEN: This method call is required by the Web Form Designe
    'Do not modify it using the code editor
    InitializeComponent(
    End Su

    #End Regio

    Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Loa
    'Put user code to initialize the page her
    If Not IsPostBack The
    bindGrid(
    Els
    'Need to do something here? Calling bindGrid() again in the Page_PreRender() even
    'to show the updated data (should be updated in the TextChanged event, but it's no
    'firing...??
    End I

    End Su

    Private Sub Page_PreRender(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.PreRende

    bindGrid(

    End Su

    'Note using the Pubs database, Sales table

    Protected Sub bindGrid(
    Dim da As SqlDataAdapte
    Dim sqlStr As Strin
    Dim ds As DataSe

    sqlStr = "Select * from Sales
    da = New SqlDataAdapter(sqlStr, CONN_STR
    ds = New DataSe

    da.Fill(ds

    DataGrid1.DataSource = ds.Tables(0
    getColumns(
    DataGrid1.DataBind(
    End Su

    'Here I'm generating my columns I want to display. I'm not giving any chance to
    'hide / show columns in this demonstration but in the real application, I woul
    'selectively generate the list of columns
    Protected Sub getColumns(
    Dim li As ArrayLis
    Dim b As BoundColum
    Dim colTem As TemplateColum

    li = New ArrayList(10
    DataGrid1.Columns.Clear(

    b = New BoundColum
    b.DataField = "stor_id
    b.HeaderText = "Store ID
    li.Add(b

    b = New BoundColum
    b.DataField = "ord_num
    b.HeaderText = "Order Number
    li.Add(b

    b = New BoundColum
    b.DataField = "ord_date
    b.HeaderText = "Order Date
    li.Add(b

    colTem = New TemplateColum
    colTem.ItemTemplate = New SupplierColum
    colTem.HeaderText = "Quantity
    li.Add(colTem

    b = New BoundColum
    b.DataField = "payterms
    b.HeaderText = "Payment Terms
    li.Add(b

    b = New BoundColum
    b.DataField = "title_id
    b.HeaderText = "Title ID
    li.Add(b

    'Add our columns to our DataGrid now..
    For Each c As DataGridColumn In l
    DataGrid1.Columns.Add(c
    Nex

    End Su

    End Clas

    '*******************************

    ' SupplierColumn Class Definitio

    '*******************************
    Public Class SupplierColum
    Implements System.Web.UI.ITemplat

    Public Sub textChanged(ByVal sender As Object, ByVal e As EventArgs
    'TODO: Complete update process here!

    CType(sender, TextBox).Page.Response.Write("TextChangedHandler")

    End Sub

    'In the bindData event, we check to see if the "qty" field of the Sales
    'table in the Pubs database is 0. If it is, then we want to display a
    'TextBox so that someone can update the value. Otherwise, we display
    'a literal with the actual value from the DB.
    '
    'Note: You will have to go and change a few values to 0 to test this out!
    Public Sub bindData(ByVal sender As Object, ByVal e As EventArgs)
    Dim t As TextBox
    Dim dg As DataGridItem
    Dim dv As DataRowView
    Dim val As String
    Dim li As Literal
    Dim qty As Integer

    t = CType(sender, TextBox)
    dg = CType(t.NamingContainer, DataGridItem)
    dv = CType(dg.DataItem, DataRowView)
    li = CType(t.Parent.Controls(0), Literal)

    val = dv("qty").ToString()
    qty = Integer.Parse(val)
    If qty = 0 Then
    t.Visible = True
    li.Visible = False
    Else
    li.Visible = True
    li.Text = val
    t.Visible = False
    End If

    End Sub

    'Required by the ITemplate Interface. I am adding my handlers here, as well as setting
    'the AutoPostBack property to True for the TextBox.
    Public Sub InstantiateIn(ByVal container As System.Web.UI.Control) Implements System.Web.UI.ITemplate.InstantiateIn

    Dim tb As TextBox
    Dim li As Literal
    tb = New TextBox
    li = New Literal
    li.ID = "LI1"
    tb.ID = "TB1"
    tb.AutoPostBack = True
    AddHandler tb.TextChanged, AddressOf textChanged
    AddHandler tb.DataBinding, AddressOf bindData

    container.Controls.Add(li)
    container.Controls.Add(tb)

    End Sub
    End Class
    David, Feb 17, 2004
    #4
  5. David

    David Guest

    Hi Jeffrey

    I think I got my code working. I moved my bindGrid() call from the Page_Load event to the Page_Init event, and that seemed to take care of the problem

    Thanks for your help
    David
    David, Feb 17, 2004
    #5
  6. Hi David,

    Thanks very much for your feedback.

    I am glad you find a way to get it work. After reviewing your original
    code, I will explain the original "Error" behavior for you. Hope it can
    help you.

    ===================================================
    When you dynamicly add TemplateColumn into the datagrid control,
    ITemplate.InstantiateIn will be called when your datagrid is
    databinding.(That is DataGrid1.DataBind() method is called). So you must
    place the TempalteColumn creation and column adding code before the
    DataGrid.DataBind method.(In your original code, you have done this, at
    this point, your code is correct)

    When page postback(In your case, your page postback is caused by
    TextChanged), the DataGrid.DataBind method will not be called(Because you
    have judged the Page.IsPostBack property). In this situation, the whole
    datagrid columns will be re-created from the ViewState. So LoadViewState
    method acts as the DataBind() method's position. So ITemplate.InstantiateIn
    will be called after LoadViewState method. To make your TemplateColumn work
    well, you must place your column into the datagrid before LoadViewState
    method is called.(Or the ITemplate.InstantiateIn will not be called) While
    in asp.net LifeCyle, LoadViewState method is called before the Load event
    and after the Init event, so when you place your code into the Init event,
    all works well.

    I think this explains your un-expected behavior of your Asp.net application.

    ===================================================
    Thank you for your patience and cooperation. If you have any questions or
    concerns, please feel free to post it in the group. I am standing by to be
    of assistance.
    Have a nice day!!

    Best regards,
    Jeffrey Tan
    Microsoft Online Partner Support
    Get Secure! - www.microsoft.com/security
    This posting is provided "as is" with no warranties and confers no rights.
    Jeffrey Tan[MSFT], Feb 18, 2004
    #6
    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. cosine... zero
    Replies:
    0
    Views:
    646
    cosine... zero
    Jun 9, 2004
  2. Chris Newby
    Replies:
    1
    Views:
    590
    =?Utf-8?B?c2FyYQ==?=
    Feb 28, 2005
  3. Replies:
    2
    Views:
    3,993
    Eliyahu Goldin
    Aug 11, 2005
  4. RA Scheltema
    Replies:
    3
    Views:
    383
    RA Scheltema
    Jan 6, 2004
  5. Replies:
    0
    Views:
    137
Loading...

Share This Page