Wrox Home  
Search P2P Archive for: Go

  Return to Index  

aspx_beginners thread: Why won't DataList display when page renders?


Message #1 by "Jon Maz" <jonmaz@s...> on Sat, 18 May 2002 01:06:43
Hi All,

I have a problem that probably takes longer to explain than to solve, so I 
hope someone has the patience to read the whole posting!  I have included 
all the relevant code below, and simplified it down as much as I can.  


THE DESIGN AND THE PROBLEM 

Basically I have a DataList bound to a DataTable.  When the page 
PreRenders, new rows are added to the DataTable, and the DataList is 
rebound to it, so the DataList SHOULD display the new data automatically 
on Page_PreRender.  This is what I want.  

But in fact these new rows are not displayed until a button is pressed (I 
DON'T want to have to wait for the button click).  The strange thing is 
that pressing the button calls exactly the same routine that 
Page_PreRender calls, so I have no idea why clicking the button causes the 
subroutine to work, while the same subroutine called from Page_PreRender 
apparently doesn't work!

In the actual code the DataList is inside a UserControl, which is within 
another UserControl, which is inside a DataGrid (!), but the basic 
principle - and basic problem - is as described above.  Now I'll try to 
explain how the page is structured, so no one has to spend too much time 
working out my code.


THE CODE EXPLAINED

There is a main aspx page ("MainPage.aspx") which holds a UserControl 
("MainUserControl.ascx") inside a DataGrid.  Within this 
MainUserControl.ascx there are two further UserControls, one on the left 
hand side of a table ("SubUserControl_LHS.ascx") and one on the right 
("SubUserControl_RHS.ascx").  The left hand UserControl has a DropDownList 
and a LinkButton, the right hand UserControl has a DataList within it.

The page is part of a forum site, and its purpose is to display and allow 
editing of a list of Author(s) of a given message (messages to this forum 
CAN have multiple authors).  The page will first pull the author(s) of a 
particular message out of an Access database, and display these names in 
the DataList in SubUserControl_RHS.ascx. 

The page user will then be able to edit this "Authors" list in two ways:

        1) by clicking on a displayed name, that name is REMOVED from the 
list of authors (this is handled by Sub myDataList_DeleteCommand within 
SubUserControl_RHS.ascx)
        
        2) the user can ADD to the list of Authors by selecting from the 
DropDownList and clicking the LinkButton in SubUserControl_LHS.ascx.

However (1) and (2) these parts of the page work fine - I have just 
included them to help understand the code.  It is the initial display of 
author(s) pulled from the Database which is NOT working.

To simplify things, I have replaced the Access query with a simple fixed 
ArrayList in MainPage.aspx:
	myAL.Add("Bob")
        myAL.Add("Jimmy")
        myAL.Add("Eric")
but this simplified code still displays the same problem.  So imagine 
that "Bob", "Jimmy" and "Eric" are the three authors of the current 
message that have been pulled from the database.

The Public Sub "AddPerson" in SubUserControl_RHS.ascx controls the adding 
of these authors to the DataTable, and then DataBinding this DataTable to 
the DataList.  When called, this subroutine checks that the passed name is 
not already in a DataTable (which itself is stored in the ViewState), and 
if the name is not a duplicate, it adds a new row to a DataTable and then 
DataBinds the DataTable.


So, when MainPage.aspx first loads, what SHOULD happen is this: 

a)  MainPage.aspx's PreRender finds the MainUserControl in the DataGrid 
and passes the Bob/Jimmy/Eric ArrayList to the DisplayNames subroutine in 
MainUserControl.ascx

b)   DisplayNames loops through this little ArrayList, each time passing a 
name to the AddPerson subroutine of SubUserControl_RHS.ascx

c)  AddTable pulls a pre-built DataTable out of the ViewState, checks that 
the name it has received is not a duplicate name, adds the name to a new 
row of the DataTable, puts the amended DataTable back into the ViewState, 
and binds the DataList to the amended DataTable.

d)  The DataList displays the added name(s)


**************** THE PROBLEM *********************
This last step (d) IS WHERE THE PROBLEM IS - the names are NOT displayed 
on Page_PreRender. 
 

In fact, the DataList displays absolutely nothing on Page_PreRender. But 
then - oddly -  if I select a name from the DropDownList in 
SubUserControl_LHS.ascx, and click the "Add User" button, the names Bob, 
Jimmy and Eric pop out of the ether and show up in the DataList, along 
with the name just selected from the DropDownList!

So it seems most of the code HAS worked!  The names Bob, Jimmy and Eric 
seem to be in the DataTable, but for some reason are NOT being displayed 
in the DataList on Page_PreRender, but only when the LinkButton is clicked 
(which is too late)

Congratulations for reading this far!  Now you understand the problem, I 
hope you can tell me what's going on and how to fix it!

Thanks in advance,

Cheers,

JON







++++++++++++++++++++++++++
MainPage.aspx
++++++++++++++++++++++++++




<%@ Page Language="VB" Trace="true" Debug="true" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.Oledb" %>

<%@ Register TagPrefix="UserControl" TagName="Article" 
src="MainUserControl.ascx" %>


<script language="VB" runat="server">


Dim myAL As New ArrayList()

Sub Page_Load(sender as object, e as eventargs)

        '*** dummy HashTable just to give the dg a shape!
        Dim myHT As New Hashtable()
        myHT.Add("ABC", "XYZ")
        dg.DataSource = myHT
        
        '*******************************************
        '*** HERE IS THE PROBLEM
        '*** These names should appear automatically
        '*** in the DataList in SubUserControl_RHS.ascx
        '*** when this MainPage.aspx PreRenders
        '*** BUT THEY DON'T!
        '*******************************************
        myAL.Add("Bob")
        myAL.Add("Jimmy")
        myAL.Add("Eric")


If Not Page.IsPostBack Then
        dg.EditItemIndex = 0	'*** DataGrid opens in Edit Mode
        dg.Databind()
        End If
End Sub



Sub Page_PreRender(sender As Object, e As EventArgs)
'*** The UserControl is not found if I do this in Page_Load

   Dim item as DataGridItem
     For Each item In dg.Items
       If (Item.ItemType = ListItemType.EditItem) then
         If Not Page.IsPostBack then
           Dim ucArticle as AddArticleTemplate = Item.FindControl
("ucArticle")
           '*** THE DISPLAYNAMES SUB IS CALLED HERE ****
           ucArticle.DisplayNames(myAL)		
         end if
       end if
   Next item

end sub


</script> 

<html>
<form runat="server">

<asp:DataGrid id="dg" runat="server" AutoGenerateColumns="False">
<Columns>
<asp:TemplateColumn>
   <EditItemTemplate>
	<UserControl:Article id="ucArticle" runat="server" />
   </EditItemTemplate>
</asp:TemplateColumn>
</Columns>
</asp:dataGrid>

</form> 
</body>
</html>







++++++++++++++++++++++++++
MainUserControl.ascx
++++++++++++++++++++++++++



<%@ Control Language="VB" ClassName="AddArticleTemplate" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.Oledb" %>

<%@ Register TagPrefix="LHS" TagName="UserControl" 
src="SubUserControl_LHS.ascxx" %>
<%@ Register TagPrefix="RHS" TagName="UserControl" 
src="SubUserControl_RHS.ascx" %>


<script language="VB" runat="server">


Sub Page_Load(obj as object, e as EventArgs)
        If not Page.IsPostBack
        	DataBind()		
        end if
end sub

		
Protected Overrides Function OnBubbleEvent(obj As Object, e As EventArgs) 
As Boolean
        '*** to detect bubble event in SubUserControl_LHS.ascx
        '*** and add selected person to DataTable in 
SubUserControl_RHS.ascx
        if obj.Text = "Add Author" then
        	RHSUserControl.AddPerson
(LHSUserControl.SelectedPersonName, LHSUserControl.SelectedPersonValue)
        end if
        Return True
End Function


'*** THIS ROUTINE SHOULD DISPLAY THE NAMES ***
Public Sub DisplayNames(objExistingMessageDetails as ArrayList)
        Dim TempAL as ArrayList = objExistingMessageDetails
        Dim myEnumerator As System.Collections.IEnumerator = 
TempAL.GetEnumerator()
        While myEnumerator.MoveNext()
        	RHSUserControl.AddPerson(myEnumerator.Current, 1)
        End While
End Sub

</script>



<asp:Table runat="server">
        <asp:TableRow>
        <asp:TableCell VerticalAlign="top" width="50%">
           <LHS:UserControl runat="server" id="LHSUserControl" />
	   </asp:TableCell><asp:TableCell width="50%">
	   <RHS:UserControl runat="server" id="RHSUserControl" />
	   </asp:TableCell>
           </asp:TableRow>	
</asp:Table>








++++++++++++++++++++++++++
SubUserControl_RHS.ascx
++++++++++++++++++++++++++



<%@ Control Language="VB" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.Oledb" %>

<script language="VB" runat="server">

Dim objDatabase as new BusinessObjects.Database
Dim ds as new DataSet()
Dim myDataTable as DataTable
Dim myColumn as DataColumn
Dim myRow as DataRow


Sub Page_Load(obj as object, e as eventargs)

objDatabase.ConnectionString = ConfigurationSettings.AppSettings
("ConnectionString")
objDatabase.DataSet = ds

	If Not IsNothing(ViewState("PeopleToAdd")) then
		myDataList.DataSource = ViewState("PeopleToAdd")
	end if

If not Page.IsPostBack
	DataBind()
	
	'*** Set up the DataTable in ViewState ***
	myDataTable = new DataTable("PeopleToAdd")
	myColumn = myDataTable.Columns.Add("PersonID", System.Type.GetType
("System.Int32"))
	myColumn.AllowDBNull = false
	myColumn = myDataTable.Columns.Add("Name", System.Type.GetType
("System.String"))
	myColumn.AllowDBNull = false
	ViewState("PeopleToAdd") = myDataTable

end if		

end sub


'*** THE DATALIST IS ADDED TO HERE **************
Public Sub AddPerson(SelectedPersonName as String, SelectedPersonValue as 
Integer) 
'*** adds to the DataTable "PeopleToAdd" in memory, holding the author(s) 
of the Item

'*** Pull the DataTable out of the ViewState
myDataTable = ViewState("PeopleToAdd")
	
'*** Check you aren't entering the same person twice
If objDatabase.CheckForDuplicateValuesInDataTable(myDataTable, "Name", 
SelectedPersonName) = true then
	lbDuplicate.Text = "Duplicate Value found! - no item added!"
Else		
'*** Add the row to the DataTable
	myRow = myDataTable.NewRow()
	myRow("PersonID") = SelectedPersonValue
	myRow("Name") = SelectedPersonName
	myDataTable.Rows.Add(myRow)
	
'*** Put everything back in the ViewState	
	ViewState("PeopleToAdd") = myDataTable
	
'*** Blank out any "duplicate found" error messages 
	lbDuplicate.Text = ""
	
	myDataList.DataBind()
	
End if
End sub



Sub myDataList_DeleteCommand(obj as object, e as DataListCommandEventArgs)
        myDataTable = ViewState("PeopleToAdd")
        myDataTable.Rows.RemoveAt(e.Item.ItemIndex)
        ViewState("PeopleToAdd") = myDataTable
        myDataList.DataBind()
        lbDuplicate.Text = ""  '*** Blank out any "duplicate found" error 
messages 
End sub



Public ReadOnly Property Authors As ArrayList
Get
	myDataTable = ViewState("PeopleToAdd")
	dim tempArrayList as New ArrayList()
	dim tempRow as DataRow
	for each tempRow in myDataTable.Rows
		tempArrayList.Add(tempRow("PersonID"))
	next tempRow		
	Return tempArrayList
End Get
End Property

</script>

<b>Authors (click to delete):</b>
<asp:DataList runat="server" 
        id="myDataList" 
        repeatlayout = "flow"
        repeatdirection = "horizontal"
        OnDeleteCommand = "myDataList_DeleteCommand">

<ItemTemplate>
	<asp:LinkButton runat="server" Text='<%# Container.DataItem
("Name") %>' CommandName="Delete" /> ///
</ItemTemplate>			

</asp:DataList>

<asp:Label runat="server" id="lbDuplicate" />



++++++++++++++++++++++++++
SubUserControl_LHS.ascx
++++++++++++++++++++++++++


<%@ Control Language="VB"  %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.Oledb" %>


<script language="VB" runat="server">

Dim objDatabase as new BusinessObjects.Database
Dim ds as new DataSet()

Dim myDataTable as DataTable
Dim myColumn as DataColumn
Dim myRow as DataRow


Sub Page_Load(obj as object, e as eventargs)

	objDatabase.ConnectionString = ConfigurationSettings.AppSettings
("ConnectionString")
	objDatabase.DataSet = ds
	ddDDL.DataSource = objDatabase.CreateDataTableDefaultView
("tblPostedBy", "SELECT tblPeople.PersonID, tblPeople.FullName FROM 
tblPeople;")
	ddDDL.DataTextField = "People"
	ddDDL.DataValueField = "PersonID"
	
	If not Page.IsPostBack
		DataBind()
	end if		
		
end sub

	
Public ReadOnly Property SelectedPersonName As String
	Get
		Return ddDDL.SelectedItem.Text
	End Get
End Property


Public ReadOnly Property SelectedPersonValue As Integer
	Get
		Return ddDDL.SelectedItem.Value
	End Get
End Property

	
</script>

Authors - choose from list:
<asp:DropDownList id="ddDDL" runat="server" />

<asp:LinkButton runat="server" Text="Add Author" id="lbLinkButton" />
Message #2 by "Jon Maz" <jonmaz@s...> on Wed, 22 May 2002 17:13:48
Hi All,

I solved the problem eventually.  In SubUserControl_RHS.ascx, I had to 
move the line: 

	myDataList.DataSource = ViewState("PeopleToAdd")

into the Page_Load If Not Page.IsPostBack subroutine, giving this:

			
If not Page.IsPostBack

myDataTable = new DataTable("PeopleToAdd")
myColumn = myDataTable.Columns.Add("PersonID", System.Type.GetType
("System.Int32"))
myColumn.AllowDBNull = false
myColumn = myDataTable.Columns.Add("Name", System.Type.GetType
("System.String"))
myColumn.AllowDBNull = false
ViewState("PeopleToAdd") = myDataTable
'**** PUT THE LINE HERE INSTEAD!
myDataList.DataSource = ViewState("PeopleToAdd")
DataBind()

end if		



Cheers,

JON

  Return to Index