|
web
newsgroups
|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
Problem creating TemplateFields in DetailsView dynamicallyI want to create a TempalteField in a DetailsView dynamically. I call the "SetDetailsTemplateFields"-Method on every Postback (Page_OnLoad). The Problem that occurs is, that on every Postback I get a new row, but the TemplateField is only created in the last row. Example: ID 10 Name Smith Memo [ ] <- TemplateField After Postback: ID 10 Name Smith Memo Memo [ ] <- TemplateField When I try to update the DetailsView I get an ArgumentOutOfRangeException. How can I make sure, that only one row is created for every TemplateField? Thanks and regards, Stefan Public Class AddTemplateToDetailsView Implements ITemplate Private m_ListItemType As ListItemType Private m_Field As New DetailField Public Sub New(ByVal _listItemType As ListItemType, ByVal _field As DetailField) m_ListItemType = _listItemType m_Field = _field End Sub Public Sub InstantiateIn(ByVal container As System.Web.UI.Control) Implements System.Web.UI.ITemplate.InstantiateIn Select Case m_ListItemType Case ListItemType.Item Select Case m_Field.ItemType.ToLower() Case "textbox_multi" Dim tb As New TextBox tb.Rows = 5 tb.TextMode = TextBoxMode.MultiLine tb.Text = "Test" container.Controls.Add(tb) Case Else End Select Case Else Throw New Exception("Unknown ListItemType.") End Select End Sub Public Sub SetDetailsTemplateFields(ByRef _dv As System.Web.UI.WebControls.DetailsView, ByVal _dvdId As String) Dim oDBSqlClient As New DBSqlClient() Dim dvFields(0) As DetailField dvFields = oDBSqlClient.GetDetailViewFields(_dvdId) Dim counter As Integer = 0 For Each dvField As DetailField In dvFields If counter <> 0 Then ReDim Preserve dvFields(counter) End If Select Case dvField.Type.ToLower() Case "template" Dim tf As TemplateField = New TemplateField() If Not String.IsNullOrEmpty(dvField.ItemType) Then tf.ItemTemplate = New AddTemplateToDetailsView(ListItemType.Item, dvField) End If If Not String.IsNullOrEmpty(dvField.EditType) Then tf.EditItemTemplate = New AddTemplateToDetailsView(ListItemType.EditItem, dvField) End If If Not String.IsNullOrEmpty(dvField.InsertType) Then tf.InsertItemTemplate = New AddTemplateToDetailsView(ListItemType.SelectedItem, dvField) End If tf.HeaderText = dvField.HeaderText _dv.Fields.Add(tf) End Select counter += 1 Next End Sub Hi Stefan,
This is a quick note to let you know that I am performing research on this issue and will get back to you as soon as possible. I appreciate your patience. Regards, Walter Wang (waw***@online.microsoft.com, remove 'online.') Microsoft Online Community Support ================================================== When responding to posts, please "Reply to Group" via your newsreader so that others may learn and benefit from your issue. ================================================== This posting is provided "AS IS" with no warranties, and confers no rights. Hi Walter,
thank you very much for your answer. The problem is just solved. The fields "id" and "name" are BoundFields. I now clear the entire DetailsView-Fields and create the bound and templatefields on every postback. Is there another way to handle this? I have another question concerning the databinding of the TemplateField. I use a SqlDataSource. The BoundFields have the DataValue-Property to bind the Update-/Insert-Parameter to the SqlDataSource. How can I bind a TemplateField to the SqlDataSource? When I try to update a dataset I allways get the error-message, that the scalar-variable is not declared. Thanks and regards, Stefan ""Walter Wang [MSFT]"" <waw***@online.microsoft.com> schrieb im Newsbeitrag Show quoteHide quote news:KjKD7aNMIHA.5204@TK2MSFTNGHUB02.phx.gbl... > Hi Stefan, > > This is a quick note to let you know that I am performing research on this > issue and will get back to you as soon as possible. I appreciate your > patience. > > > Regards, > Walter Wang (waw***@online.microsoft.com, remove 'online.') > Microsoft Online Community Support > > ================================================== > When responding to posts, please "Reply to Group" via your newsreader so > that others may learn and benefit from your issue. > ================================================== > > This posting is provided "AS IS" with no warranties, and confers no > rights. > Hi Stefan,
Thanks very much for your update. I have done some research and I think we need to use another approach to create dynamic TemplateField at runtime. Apparently the added field's name is saved in ViewState, but ItemTemplate and EditItemTemplate is not, that's why you will see duplicate rows in your first message. On the other hand, if we only create the new TemplateField upon page's first load (Not Me.IsPostBack) and set the ItemTemplate and EditItemTemplate every time, we cannot extract the values from the EditItemTemplate when updating, due to some internal implementation detail of DetailsView. This turns out not a trivial task to do. We need to create all three types of classes here: * a customized DetailsView class to override CreateFieldSet and add your dynamic TemplateField * a customized TemplateField class to override the ExtractValuesFromCell method to return the data from its template, which is needed by the data layer * customized ItemTemplate and EditItemTemplate I'm include the complete code listing here for your reference (I'm using the Northwind sample database from SqlServer): Imports System Imports System.Web Imports System.Data Imports System.Web.UI Imports System.Web.UI.WebControls Public Class MyStringItemTemplate Implements ITemplate Private m_column As String Public Sub New(ByVal column As String) m_column = column End Sub Public Sub InstantiateIn(ByVal container As System.Web.UI.Control) Implements System.Web.UI.ITemplate.InstantiateIn Dim l As New Literal() AddHandler l.DataBinding, AddressOf BindData container.Controls.Add(l) End Sub Protected Sub BindData(ByVal sender As Object, ByVal e As EventArgs) Dim l As Literal = sender Dim dv As DetailsView = l.NamingContainer l.Text = DataBinder.Eval(dv.DataItem, m_column) End Sub End Class Public Class MyStringEditItemTemplate Implements ITemplate Private m_column As String Public Sub New(ByVal column As String) m_column = column End Sub Public Sub InstantiateIn(ByVal container As System.Web.UI.Control) Implements System.Web.UI.ITemplate.InstantiateIn Dim tb As New TextBox() tb.ID = m_column AddHandler tb.DataBinding, AddressOf BindData container.Controls.Add(tb) End Sub Protected Sub BindData(ByVal sender As Object, ByVal e As EventArgs) Dim tb As TextBox = sender Dim dv As DetailsView = tb.NamingContainer tb.Text = DataBinder.Eval(dv.DataItem, m_column) End Sub End Class Public Class MyTemplateField Inherits TemplateField Private m_column As String Public Sub New(ByVal column As String) ItemTemplate = New MyStringItemTemplate(column) EditItemTemplate = New MyStringEditItemTemplate(column) m_column = column End Sub Public Overrides Sub ExtractValuesFromCell(ByVal dictionary As System.Collections.Specialized.IOrderedDictionary, ByVal cell As System.Web.UI.WebControls.DataControlFieldCell, ByVal rowState As System.Web.UI.WebControls.DataControlRowState, ByVal includeReadOnly As Boolean) MyBase.ExtractValuesFromCell(dictionary, cell, rowState, includeReadOnly) Dim tb As TextBox = cell.FindControl(m_column) dictionary(m_column) = tb.Text End Sub End Class Public Class MyDetailsView Inherits DetailsView Protected Overrides Function CreateFieldSet(ByVal dataItem As Object, ByVal useDataSource As Boolean) As System.Collections.ICollection Dim col As New MyTemplateField("Description") Dim al As New ArrayList() For Each f As DataControlField In MyBase.CreateFieldSet(dataItem, useDataSource) al.Add(f) Next al.Add(col) Return al End Function End Class <%@ Page Language="vb" AutoEventWireup="false" CodeBehind="WebForm2.aspx.vb" Inherits="WebApplication2.WebForm2" %> <%@ Register assembly="WebApplication2" namespace="WebApplication2" tagprefix="cc1" %> <!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> <cc1:MyDetailsView ID="MyDetailsView1" runat="server" AutoGenerateRows="False" AutoGenerateEditButton="true" DataKeyNames="CategoryID" DataSourceID="SqlDataSource1"> <Fields> <asp:BoundField DataField="CategoryID" HeaderText="ID" ReadOnly="True" SortExpression="CategoryID" /> <asp:BoundField DataField="CategoryName" HeaderText="Name" SortExpression="CategoryName" /> </Fields> </cc1:MyDetailsView> <asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>" SelectCommand="SELECT [CategoryID], [CategoryName], [Description] FROM [Categories]" UpdateCommand="UPDATE [Categories] Set [CategoryName]=@CategoryName, [Description]=@Description where [CategoryID]=@CategoryID" > </asp:SqlDataSource></div> </form> </body> </html> Hope this helps. Regards, Walter Wang (waw***@online.microsoft.com, remove 'online.') Microsoft Online Community Support ================================================== When responding to posts, please "Reply to Group" via your newsreader so that others may learn and benefit from your issue. ================================================== This posting is provided "AS IS" with no warranties, and confers no rights. Hi Walter,
thank you very much for your detailed answer. I need some time for testing and then I'll let you know, if I could solve the problem. Thanks and regards, Stefan ""Walter Wang [MSFT]"" <waw***@online.microsoft.com> schrieb im Newsbeitrag Show quoteHide quote news:ALLe$1iMIHA.5204@TK2MSFTNGHUB02.phx.gbl... > Hi Stefan, > > Thanks very much for your update. > > I have done some research and I think we need to use another approach to > create dynamic TemplateField at runtime. > > Apparently the added field's name is saved in ViewState, but ItemTemplate > and EditItemTemplate is not, that's why you will see duplicate rows in > your > first message. On the other hand, if we only create the new TemplateField > upon page's first load (Not Me.IsPostBack) and set the ItemTemplate and > EditItemTemplate every time, we cannot extract the values from the > EditItemTemplate when updating, due to some internal implementation detail > of DetailsView. > > This turns out not a trivial task to do. We need to create all three types > of classes here: > > * a customized DetailsView class to override CreateFieldSet and add your > dynamic TemplateField > * a customized TemplateField class to override the ExtractValuesFromCell > method to return the data from its template, which is needed by the data > layer > * customized ItemTemplate and EditItemTemplate > > I'm include the complete code listing here for your reference (I'm using > the Northwind sample database from SqlServer): > > Imports System > Imports System.Web > Imports System.Data > Imports System.Web.UI > Imports System.Web.UI.WebControls > > Public Class MyStringItemTemplate > Implements ITemplate > > Private m_column As String > Public Sub New(ByVal column As String) > m_column = column > End Sub > > Public Sub InstantiateIn(ByVal container As System.Web.UI.Control) > Implements System.Web.UI.ITemplate.InstantiateIn > Dim l As New Literal() > AddHandler l.DataBinding, AddressOf BindData > container.Controls.Add(l) > End Sub > > Protected Sub BindData(ByVal sender As Object, ByVal e As EventArgs) > Dim l As Literal = sender > Dim dv As DetailsView = l.NamingContainer > l.Text = DataBinder.Eval(dv.DataItem, m_column) > End Sub > End Class > > Public Class MyStringEditItemTemplate > Implements ITemplate > > Private m_column As String > Public Sub New(ByVal column As String) > m_column = column > End Sub > Public Sub InstantiateIn(ByVal container As System.Web.UI.Control) > Implements System.Web.UI.ITemplate.InstantiateIn > Dim tb As New TextBox() > tb.ID = m_column > AddHandler tb.DataBinding, AddressOf BindData > container.Controls.Add(tb) > End Sub > Protected Sub BindData(ByVal sender As Object, ByVal e As EventArgs) > Dim tb As TextBox = sender > Dim dv As DetailsView = tb.NamingContainer > tb.Text = DataBinder.Eval(dv.DataItem, m_column) > End Sub > End Class > > Public Class MyTemplateField > Inherits TemplateField > > Private m_column As String > Public Sub New(ByVal column As String) > ItemTemplate = New MyStringItemTemplate(column) > EditItemTemplate = New MyStringEditItemTemplate(column) > m_column = column > End Sub > > Public Overrides Sub ExtractValuesFromCell(ByVal dictionary As > System.Collections.Specialized.IOrderedDictionary, ByVal cell As > System.Web.UI.WebControls.DataControlFieldCell, ByVal rowState As > System.Web.UI.WebControls.DataControlRowState, ByVal includeReadOnly As > Boolean) > MyBase.ExtractValuesFromCell(dictionary, cell, rowState, > includeReadOnly) > Dim tb As TextBox = cell.FindControl(m_column) > dictionary(m_column) = tb.Text > End Sub > End Class > > Public Class MyDetailsView > Inherits DetailsView > > Protected Overrides Function CreateFieldSet(ByVal dataItem As Object, > ByVal useDataSource As Boolean) As System.Collections.ICollection > Dim col As New MyTemplateField("Description") > > Dim al As New ArrayList() > For Each f As DataControlField In MyBase.CreateFieldSet(dataItem, > useDataSource) > al.Add(f) > Next > al.Add(col) > Return al > End Function > End Class > > > > <%@ Page Language="vb" AutoEventWireup="false" > CodeBehind="WebForm2.aspx.vb" Inherits="WebApplication2.WebForm2" %> > > <%@ Register assembly="WebApplication2" namespace="WebApplication2" > tagprefix="cc1" %> > > <!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> > > <cc1:MyDetailsView ID="MyDetailsView1" runat="server" > AutoGenerateRows="False" > AutoGenerateEditButton="true" DataKeyNames="CategoryID" > DataSourceID="SqlDataSource1"> > <Fields> > <asp:BoundField DataField="CategoryID" HeaderText="ID" > ReadOnly="True" > SortExpression="CategoryID" /> > <asp:BoundField DataField="CategoryName" HeaderText="Name" > SortExpression="CategoryName" /> > </Fields> > </cc1:MyDetailsView> > <asp:SqlDataSource ID="SqlDataSource1" runat="server" > ConnectionString="<%$ > ConnectionStrings:NorthwindConnectionString %>" > SelectCommand="SELECT [CategoryID], [CategoryName], > [Description] FROM [Categories]" > UpdateCommand="UPDATE [Categories] Set > [CategoryName]=@CategoryName, [Description]=@Description where > [CategoryID]=@CategoryID" > > > </asp:SqlDataSource> > > </div> > </form> > </body> > </html> > > > Hope this helps. > > > Regards, > Walter Wang (waw***@online.microsoft.com, remove 'online.') > Microsoft Online Community Support > > ================================================== > When responding to posts, please "Reply to Group" via your newsreader so > that others may learn and benefit from your issue. > ================================================== > > This posting is provided "AS IS" with no warranties, and confers no > rights. >
Other interesting topics
{0:c} causes input string not in correct format exception
Reload/refresh data in datagrid GridView is making two of each column wrap text in datagrid cell Rendering a GridView Updating SelectedIndex after delete wrapping text in datagrid Making an entire column visible/not visible. Programattically setting gridview to edit mode Modfying bound data in a GridView? |
|||||||||||||||||||||||