Link to home
Start Free TrialLog in
Avatar of riceman0
riceman0

asked on

Can't switch modes with DetailsView TemplateField? (Anyone? Bueller?)

(This is the third time I've re-posted this question, trying to get attention.  I'm pretty surprised I can't get anyone to look at it.  I've wrapped it up as best as I can, nobody will even try my cut-and-paste code and say "works for me" or "yeah that's weird"??  There appears to be lots of knowledge on this site on DetailsViews, and I'm having some stubborn trouble, and I'm sure it's something simple I'm not doing.  Please, if you're an expert on this stuff and don't like this question, let me know how to rephrase it... or if you can suggest alternate approaches...  )

Hey.  I'm having trouble with switching modes in my DetailsView.  I'm not using a real database, just my own DataTable (which I think should work fine).  It works fine (switching between modes, saving data or not) with BoundFields and CheckBox fields, but when I create my own TemplateField (with a combo box), the controls seem to disappear.

I've provided cut-and-paste code to show the problem.  Create a new webform and (just tested this, works fine):

a) Drop DetailsView1 on it
b) Replace the VB code behind it with the code below.
c) Add the attribute EnableEventValidation="false" to the Page item on the page source, mine looks like:

<%@ Page Language="VB" AutoEventWireup="false" CodeFile="FormTest3.aspx.vb" Inherits="FormTest3" EnableEventValidation="false"%>

And you'll see the problem.  Change the data and click "update", and the data saves (into my DataTable, where I can process it on the server), or cancel and it doesn't save.  Then go back to Edit mode and so on.  *Except* for my TemplateField, which seems to go blank on any mode change.

Somehow I'm missing something special that is needed to keep my TemplateField active, an event handler or something.

If anyone has ANY ideas, I'd love to hear them.  This problem has been my showstopper for several days now.  Thanks VERY much.
Partial Class FormTest2
    Inherits System.Web.UI.Page
 
    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
 
        If Not IsPostBack Then
 
            ' ****************************************
            '
            ' if I start it out in edit mode, then the combo box template displays
            ' fine, with the dummy defined values
            '
            ' if I start it out in readonly mode, then the label template displays
            ' fine, with the dummy text
            '
            ' but in either case, when I switch to the other mode, the 
            ' template does not display, it's just a blank field
            '
            ' (I do have to set Page EnableEventValidation="false" for some 
            ' reason, or the combo box belches)
            ' 
            ' (was going to add code to set/read the combo box, but for now 
            ' just can't get it to display)
            '
            ' ****************************************
 
            DetailsView1.DefaultMode = DetailsViewMode.Edit
            'DetailsView1.DefaultMode = DetailsViewMode.ReadOnly
 
            ' ****************************************
            ' build a datatable
            ' add columns 'Field1' and 'Field2'
            ' ****************************************
 
            Dim dt As New Data.DataTable
            Session("stored_datatable") = dt
 
            Dim bc As New Data.DataColumn
            bc.ColumnName = "Field1"
            dt.Columns.Add(bc)
 
            Dim bc2 As New Data.DataColumn
            bc2.ColumnName = "Field2"
            dt.Columns.Add(bc2)
 
            Dim bc3 As New Data.DataColumn
            bc3.ColumnName = "Field3"
            dt.Columns.Add(bc3)
 
            Dim bc4 As New Data.DataColumn
            bc4.ColumnName = "Field4"
            dt.Columns.Add(bc4)
 
            ' ****************************************
            ' build the details view to match
            ' ****************************************
 
            With DetailsView1
 
                .AutoGenerateRows = False
                .AutoGenerateEditButton = True
 
                Dim dcf As New BoundField
                dcf.DataField = "Field1"
                dcf.HeaderText = "Field1"
                .Fields.Add(dcf)
 
                Dim dcf2 As New BoundField
                dcf2.DataField = "Field2"
                dcf2.HeaderText = "Field2"
                .Fields.Add(dcf2)
 
                Dim dcf3 As New CheckBoxField
                dcf3.DataField = "Field3"
                dcf3.HeaderText = "Field3"
                .Fields.Add(dcf3)
 
                Dim dcf4 As New TemplateField()
 
                Dim temp_cmb As New TemplateComboBox()
                Dim temp_lbl As New TemplateLabel()
 
                dcf4.ItemTemplate = temp_lbl
                dcf4.EditItemTemplate = temp_cmb
                dcf4.HeaderText = "Field4"
                .Fields.Add(dcf4)
 
            End With
 
            ' ****************************************
            ' add a single row to the datatable
            ' ****************************************
 
            dt.Rows.Add("data1", "data2", True, 3)
 
            ' ****************************************
            ' and bind
            ' ****************************************
 
            DetailsView1.DataSource = dt
            DetailsView1.DataBind()
 
        End If
 
    End Sub
 
    Protected Sub DetailsView1_ModeChanging(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.DetailsViewModeEventArgs) Handles DetailsView1.ModeChanging
 
        ' ****************************************
        ' handle the mode change
        ' rebind to the source table
        ' ****************************************
 
        Dim dv As DetailsView = sender
 
        Dim dt As Data.DataTable = Session("stored_datatable")
 
        dv.DataSource = dt
 
        Select Case e.NewMode
 
            Case DetailsViewMode.ReadOnly : dv.ChangeMode(DetailsViewMode.ReadOnly)
            Case DetailsViewMode.Edit : dv.ChangeMode(DetailsViewMode.Edit)
            Case DetailsViewMode.Insert : dv.ChangeMode(DetailsViewMode.Insert)
 
        End Select
 
        dv.DataBind()
 
    End Sub
 
    Protected Sub DetailsView1_ItemUpdating(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.DetailsViewUpdateEventArgs) Handles DetailsView1.ItemUpdating
 
        ' ****************************************
        ' handle the item update
        ' must admit: don't know why all this is necessary, got it from EE
        ' maybe it will become clear later
        ' ****************************************
 
        Dim dv As DetailsView = sender
        Dim dt As Data.DataTable = Session("stored_datatable")
 
        For i As Integer = 0 To dv.Fields.Count - 1
 
            Dim cn As DataControlFieldCell = dv.Rows(i).Cells(0)
            dv.Fields(i).ExtractValuesFromCell(e.Keys, cn, DataControlRowState.Normal, True)
 
            Dim ce As DataControlFieldCell = dv.Rows(i).Cells(1)
            dv.Fields(i).ExtractValuesFromCell(e.NewValues, ce, DataControlRowState.Edit, False)
 
        Next
 
        Dim cnt As Integer = 0
 
        For Each key As String In e.NewValues.Keys
            dt.Rows(0).Item(cnt) = e.NewValues(key)
            cnt += 1
        Next
 
        dv.DataSource = dt
        dv.ChangeMode(DetailsViewMode.ReadOnly)
        dv.DataBind()
 
    End Sub
 
    ' ****************************************
    ' my template classes for the combo box
    ' ****************************************
 
    Public Class TemplateComboBox
 
        Implements ITemplate
 
        Dim WithEvents m_combobox As New DropDownList
 
        Public Sub New()
 
            Dim L1 As New ListItem
            L1.Text = "Choice1"
            L1.Value = "1"
            m_combobox.Items.Add(L1)
            Dim L2 As New ListItem
            L2.Text = "Choice2"
            L2.Value = "2"
            m_combobox.Items.Add(L2)
 
        End Sub
 
        Public Sub InstantiateIn(ByVal container As System.Web.UI.Control) Implements System.Web.UI.ITemplate.InstantiateIn
 
            container.Controls.Add(m_combobox)
 
        End Sub
 
    End Class
 
    Public Class TemplateLabel
 
        Implements ITemplate
 
        Dim m_label As New Label
 
        Public Sub New()
 
            m_label.Text = "dummy text"
 
        End Sub
 
        Public Sub InstantiateIn(ByVal container As System.Web.UI.Control) Implements System.Web.UI.ITemplate.InstantiateIn
 
            container.Controls.Add(m_label)
 
        End Sub
 
    End Class
 
End Class

Open in new window

Avatar of raterus
raterus
Flag of United States of America image

You have the dynamic control blues, that is any controls you create dynamically, you have to rebuild them on each postback.

Basically if you want this to work, you have to run the following code (below) on each postback in page_load to rebuild the controls in the DetailsView.


            With DetailsView1
 
                .AutoGenerateRows = False
                .AutoGenerateEditButton = True
 
                Dim dcf As New BoundField
                dcf.DataField = "Field1"
                dcf.HeaderText = "Field1"
                .Fields.Add(dcf)
 
                Dim dcf2 As New BoundField
                dcf2.DataField = "Field2"
                dcf2.HeaderText = "Field2"
                .Fields.Add(dcf2)
 
                Dim dcf3 As New CheckBoxField
                dcf3.DataField = "Field3"
                dcf3.HeaderText = "Field3"
                .Fields.Add(dcf3)
 
                Dim dcf4 As New TemplateField()
 
                Dim temp_cmb As New TemplateComboBox()
                Dim temp_lbl As New TemplateLabel()
 
                dcf4.ItemTemplate = temp_lbl
                dcf4.EditItemTemplate = temp_cmb
                dcf4.HeaderText = "Field4"
                .Fields.Add(dcf4)
 
            End With

Open in new window

Avatar of riceman0
riceman0

ASKER

Thanks very much for the answer!!!

Will play around with that further, but when I try that on every reload it seems to add more and more fields to the control... which seems to suggest it does not need rebuilding... ?  Is this still the "dynamic control blues" (thanks for the concept) you're talking about?  After all I actually dropped the DetailsView in the designer, and it is visible in the ASP source, not instantiated in the code behind (it's just my DataTable that is created in the code behind).  Doesn't that make it statically created?

I will play around right now with recreating my TemplateField on every load though.  Maybe that element defies client-side persistence or something.  Of course I just sort of made up those words.
Actually, I was baffled that those other controls weren't disappearing, usually it's all or nothing.  I figured you still were down with the blues (the most common issue, by far, I see on this boards)  How does your .aspx page look, specifically the DetailsView?

No, any control you instantiate itself, and add to another control's controls section is a "dynamic" control.  The only thing I can gather about your issue is that the DetailsView can actually persist the very basic of columns.  Since the Templatefield is a bit more uncommon, it doesn't mess with that.  I dunno, I've never tested it and if it is like this, I've never seen another control act in this manner.

In the designer (if that's what you mean...) the DetailsView is just an empty control, the default three fields.

But it's funny, on inspection the DetailsView seems to retain nearly all of its properties on postbacks, like .AutoGenerateRows remains false, and it keeps the 4 fields (even though I only define them on the original load).  The fourth field even remains a TemplateField -- however both the EditItemTemplate and ItemTemplate properties of the TemplateField have vaporized to 'Nothing.'  Seems like everything is persistent but those template pointers.  I'll try to refresh those template references every time (although I have a faint recollection of trying that before to no avail, and concluded something more fundamental was wrong...)
Switch to the HTML view and find something like <asp:DetailsView ...>  Post everything around that.  I think your designer is already adding these fields that are retaining their value, which is expected..

As empty as can be, right?  That runat=server is interesting, although I assume that's default...
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:DetailsView ID="DetailsView1" runat="server" Height="50px" Width="125px">
        </asp:DetailsView>
    
    </div>
    </form>
</body>
</html>

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of raterus
raterus
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
By the way I had to set this aside for a few days (fighting a fire on a different project) but I will get back to it  ASAP, and I do appreciate the help!
Haven't licked this problem yet, I'm just closing this out to award the points to the deserving parties.  Will post the solution when I achieve it.