630 Chapter 13 • Creating a Message Board with ADO and XML
Figure 13.51 Continued
list = dotBoardObjects.MessageBoard.GetBoards()
myBoards.Tables.Add("boards")
Dim myTable As DataTable = myBoards.Tables(0) myTable.Columns.Add("BoardName", GetType(String)) myTable.Columns.Add("BoardDescription", GetType(String))
Dim i As Integer
For i = 0 To list.Count - 1
Dim myBoard As dotBoardObjects.Board
myBoard = CType(list(i), dotBoardObjects.Board) Dim fields(1) As Object
fields(0) = myBoard.Name fields(1) = myBoard.Description
myTable.Rows.Add(fields)
myTable.AcceptChanges() Next i
myBoards.AcceptChanges()
Repeater1.DataMember = "boards"
Repeater1.DataSource = myBoards
Repeater1.DataBind()
End Sub
Notice the addition to the Page_Load method in this file.This subroutine now calls the DisplayBoards subroutine. DisplayBoards restructures the list of Boards into an appropriate form for a Repeater control to use. First, it creates a DataSet and gets the list of Boards from the MessageBoard class. Next, it creates a new table in the DataSet and adds three columns to it. Next, it loops through the list of Boards and builds an object array of the fields to add to the DataSet. It then adds a new row by passing in the object array to the Add method of the
Creating a Message Board with ADO and XML • Chapter 13 |
631 |
Rows collection. Finally, it accepts the changes, and forces the Repeater control to DataBind to the DataSet. Look at Figure 13.52 to see what this page looks like.
Figure 13.52 The Default Page with Boards Displayed
Thread Browsing
Once the user has clicked one of the board links from default.aspx, they are taken to board.aspx.This page will be responsible for determining which board was selected and for displaying the appropriate threads. Displaying the Threads in a Board will function nearly identically to how displaying Boards functioned. Let’s take a look at the important quasi-HTML that this page uses in Figure 13.53.
Figure 13.53 The ASPX Code for Board.aspx
<table cellpadding="0" cellspacing="0" border="0">
<asp:Repeater runat="server" id="Repeater1">
<SeparatorTemplate>
<tr> <td colspan="2"> </td> </tr>
</SeparatorTemplate>
<ItemTemplate>
<tr>
<td>
Continued
632 Chapter 13 • Creating a Message Board with ADO and XML
Figure 13.53 Continued
started by
<%#DataBinder.Eval(Container, "DataItem.creatorName")%>
</td>
<td>
<%#DataBinder.Eval(Container, "DataItem.postCount")%> total posts
</td>
</tr>
<tr>
<td colspan="2">
<a href='thread.aspx?
<%#DataBinder.Eval(Container, "DataItem.threadLink")%>
'>
<%#DataBinder.Eval(Container, "DataItem.threadSubject")%> </a>
</td>
</tr>
</ItemTemplate>
</asp:Repeater>
</table>
The repeater code creates a separator template and the actual item template. It DataBinds the appropriate fields in the data source to items in the template. Let’s take a look at how we get the data into the data source in Figure 13.54.
Figure 13.54 Board.aspx.vb
Private Sub Page_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
Dim mBoard As dotBoardObjects.board
Dim boardId As String
boardId = Request.QueryString.Item("boardid")
Dim myLabel As Label
myLabel = CType(Me.FindControl("lblHeader"), Label)
Continued
Creating a Message Board with ADO and XML • Chapter 13 |
633 |
Figure 13.54 Continued
myLabel.Text = boardId
mBoard = New dotBoardObjects.board(boardId)
Dim myThreads As DataSet myThreads = New DataSet() myThreads.Tables.Add("threads")
Dim myTable As DataTable myTable = myThreads.Tables(0)
myTable.Columns.Add("threadLink", GetType(String)) myTable.Columns.Add("threadSubject", GetType(String)) myTable.Columns.Add("postCount", GetType(Integer)) myTable.Columns.Add("creatorName", GetType(String))
Dim i As Integer
For i = 0 To mBoard.ChildThreads.Count - 1 Dim myThread As dotBoardObjects.Thread myThread = mBoard.ChildThreads.Item(i)
Dim fields(3) As Object
fields(0) = "BoardId=" & boardId & _ "&ThreadId=" & myThread.ID.ToString()
fields(1) = myThread.Subject fields(2) = myThread.ChildPosts.Count fields(3) = myThread.Creator.Username
myTable.Rows.Add(fields)
myTable.AcceptChanges() Next i
myThreads.AcceptChanges()
Continued
634 Chapter 13 • Creating a Message Board with ADO and XML
Figure 13.54 Continued
Repeater1.DataMember = "threads"
Repeater1.DataSource = myThreads
Repeater1.DataBind()
Me.ApplyStyles(Me.Controls)
End Sub
Just like default.aspx, the data binding is relatively straightforward. First, we need to get a reference to the current Board.We do this by requesting the board name from the query string and initializing the board using it. Next, we set a label’s text property to the name of the board, so the user knows what board he’s in.Then we create a DataSet, add a table to it, and add all the required columns. Afterward, we iterate through the Board’s child threads and create an object array to hold the necessary fields to add to the DataSet. Finally, we add all the rows to the DataSet and force the Repeater control to DataBind.Take a look at Figure 13.55 to see what the completed page looks like.
Figure 13.55 The Board Page with Threads Displayed
Creating a Message Board with ADO and XML • Chapter 13 |
635 |
Message Browsing
The last piece to browsing the message board is to see individual Posts themselves. Just like Boards and Threads, displaying this data is accomplished by using a Repeater control and a DataSet. Let’s take a look at the important quasi-HTML and the code-behind in Figures 13.56 and 13.57.
Figure 13.56 Thread.aspx
<asp:Repeater runat="server" id="Repeater1"> <ItemTemplate>
<tr>
<td>posted by
<%#DataBinder.Eval(Container, "DataItem.postCreatorName")%> <%#DataBinder.Eval(Container, "DataItem.postCreatorEmail")%> </td>
<td>
posted at
<%#DataBinder.Eval(Container, "DataItem.postDate")%> </td>
</tr>
<tr>
<td colspan="2"> <b>
<%#DataBinder.Eval(Container, "DataItem.postSubject")%>
</b>
</td>
</tr>
<tr>
<td colspan="2">
<%#DataBinder.Eval(Container, "DataItem.postBody")%> </td>
</tr>
</ItemTemplate>
</asp:Repeater>
636 Chapter 13 • Creating a Message Board with ADO and XML
Figure 13.57 Thread.aspx.vb
Private Sub Page_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
Dim boardId As String
Dim threadId As Long
boardId = Request.QueryString.Item("boardId") threadId = CLng(Request.QueryString.Item("threadId"))
Dim myBoard As dotBoardObjects.board
myBoard = New dotBoardObjects.board(boardId)
Dim myThread As dotBoardObjects.thread myThread = myBoard.ChildThread(threadId)
lblHeaderBoard.Text = myBoard.Name lblHeaderThread.Text = myThread.Subject
Dim myPosts As DataSet myPosts = New DataSet() myPosts.Tables.Add("posts")
Dim myTable As DataTable myTable = myPosts.Tables(0)
myTable.Columns.Add("postId", GetType(Long)) myTable.Columns.Add("postSubject", GetType(String)) myTable.Columns.Add("postBody", GetType(String)) myTable.Columns.Add("postDate", GetType(Date)) myTable.Columns.Add("postCreatorName", GetType(String)) myTable.Columns.Add("postCreatorEmail", GetType(String))
Dim i As Integer
For i = 0 To myThread.ChildPosts.Count - 1
Continued
Creating a Message Board with ADO and XML • Chapter 13 |
637 |
Figure 13.57 Continued
Dim myPost As dotBoardObjects.Post myPost = myThread.ChildPosts.Item(i)
Dim fields(5) As Object fields(0) = myPost.ID fields(1) = myPost.Subject fields(2) = myPost.Body fields(3) = myPost.PostDate
fields(4) = myPost.Creator.Username If Me.IsLoggedIn = True Then
fields(5) = "<a href='mailto:" & myPost.Creator.Email & _ "'>email</a>"
Else
fields(5) = "" End If
myTable.Rows.Add(fields)
myTable.AcceptChanges() Next i
myPosts.AcceptChanges()
Repeater1.DataMember = "posts"
Repeater1.DataSource = myPosts
Repeater1.DataBind()
Me.ApplyStyles(Me.Controls)
End Sub
Again, this code is nearly identical to that of the last two pages we’ve dealt with.The only real difference is that one of the fields is actually building a short HTML string.This is because the repeater can’t handle if statements. So, in order to hide or show users’ e-mail addresses depending on whether the viewer is
638 Chapter 13 • Creating a Message Board with ADO and XML
logged in or not, we need to build a string instead of directly inserting the value. If the user is logged in, then the anchor tag for the poster’s e-mail address is built; otherwise, an empty string is used.
Creating the User Functions
Registered users (Members) get a special set of functions they can access, like creating threads and posts, editing their profile, and editing the messages they’ve posted. A guest (that is, an unregistered user) is limited to a very small set of func- tionalities—specifically, viewing the threads and messages (see Figure 13.58).
Figure 13.58 The Thread Page
Editing the Member Profile
The next step in building our application’s User Interface is to allow a registered user to modify his or her member profile.This includes first name, last name, password, and e-mail address. Let’s take a look at the profile.aspx page in Figure 13.59.
The profile page contains text boxes for every field in the User object, except for the user ID and username.These two fields are read only, and should never be changed. Like the register page, this page contains a number of Validation controls with their display value set to none, and a ValidationSummary control added to
Creating a Message Board with ADO and XML • Chapter 13 |
639 |
the page to aggregate all the errors a user might receive while inputting information.When this page first loads, it should default all fields (except for passwords) with their existing values, so a user does not have to type everything over, just change the fields he or she wants to change. Upon clicking the Update Profile button, the user’s details should be updated and the user given a message explaining that their profile was updated. Let’s take a look at the implementation of these features in Figure 13.60.
Figure 13.59 The Profile Page
Figure 13.60 The Code-Behind (Profile.aspx.vb)
Private Sub Page_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
If Me.IsLoggedIn = False Then
'only logged in users can access this site Response.Redirect("default.aspx")
End If
If Page.IsPostBack = False Then txtFirstName.Text = Me.CurrentUser.FirstName txtLastname.Text = Me.CurrentUser.LastName
Continued