Dynamic controls problem

G

Guest

Hi,
I am creating textbox, radiobuttonlist and checkboxlist dynamically
depending on data from a table. It is a questionnaire.
I add the control on a Panel control during the 1st load_page event.
Each question is displayed and answered, then result written to a SQL table.
Then the next question is read from a table and displayed using the
load_page event again.

The questions display and function perfectly. The user anwers the question
according to type (checkboxes,radiobuttons,textbox) and pressing a "Next"
button.

I then attempt to determine the type of question it was to process it
accordingly.
The following is a snippet of my code and the error message.

In load_page event:
Dim myROptions As RadioButtonList = New RadioButtonList
myROptions.Items.Add(CStr(MyReader("ChoiceText")))
Do While MyReader.Read 'read rest
myROptions.Items.Add(CStr(MyReader("ChoiceText")))
Loop
myROptions.ID = "myOpt"
pnlBoard.Controls.Add(myROptions)


Exception Details: System.NullReferenceException: Object reference not set
to an instance of an object.

From my Next button event:

Line 591: Dim dmyROpt As RadioButtonList
Line 592: dmyROpt = CType(pnlBoard.FindControl("myOpt"),
RadioButtonList)
Line 593: If myROptions.SelectedIndex > -1 Then
Line 594: DataChanged = True
Line 595: End If


What am I doing wrong? Please important deadline to meet....
txs,
 
G

Guest

Hi Karl,

This is my code....
I didn't think there was a postback until after the button click event was
completed. Am I wrong in my thinking? New to asp.net so I'm at your
mercy...tks Bill

Imports System.Data.SqlClient
Imports System.Text.RegularExpressions
Imports Surveys.SurveysLibrary
Imports Surveys.CCExceptionLog
Imports System.Web.UI
Imports System.Web.UI.WebControls
Imports System.Web.UI.HtmlControls

Public Class Main
Inherits System.Web.UI.Page
Protected WithEvents lblFooter As System.Web.UI.WebControls.Label
Protected WithEvents pnlNote As System.Web.UI.WebControls.Panel
Protected WithEvents lblLoginName As System.Web.UI.WebControls.Label
Protected WithEvents lblHeader As System.Web.UI.WebControls.Label
Protected WithEvents pnlStatement As System.Web.UI.WebControls.Panel
Protected WithEvents pnlParticipants As System.Web.UI.WebControls.Panel
Protected WithEvents pnlBoard As System.Web.UI.WebControls.Panel
Protected WithEvents pnlPrevious As System.Web.UI.WebControls.Panel
Protected WithEvents imgDepartment As System.Web.UI.WebControls.Image
Protected WithEvents pnlNext As System.Web.UI.WebControls.Panel
Protected WithEvents lblQuestionNum As System.Web.UI.WebControls.Label
Protected WithEvents pnlHelp As System.Web.UI.WebControls.Panel
Protected WithEvents imgbPrevious As System.Web.UI.WebControls.ImageButton
Protected WithEvents imgbNext As System.Web.UI.WebControls.ImageButton
Protected WithEvents MiscErrors As System.Web.UI.WebControls.Literal
Protected WithEvents pnlErrors As System.Web.UI.WebControls.Panel
Protected WithEvents imgbHelp As System.Web.UI.WebControls.ImageButton
Protected WithEvents pnlQuestionNum As System.Web.UI.WebControls.Panel
Protected WithEvents lblTitle As System.Web.UI.WebControls.Label
Protected WithEvents myROptions As
System.Web.UI.WebControls.RadioButtonList
Protected WithEvents myCOptions As System.Web.UI.WebControls.CheckBoxList

Private Sub Page_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
'Put user code to initialize the page here
Const MethodName As String = "Page_Load"

If Not Page.IsPostBack Then
SetTimeoutLengthForSession()
MiscErrors.Text = ""

SetUpPageData() 'Get survey header and footer info to write
on pages.
'Temporary assignment until a survey selection screen is
created....bj
SurveyNum = 1

'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'Set starting question number
CurrentQuestion = 1

'Paint question and answer options on page.
GetQuestion(SurveyNum, CurrentQuestion) '
Else
GetQuestion(SurveyNum, CurrentQuestion) '
End If
End Sub

Private Sub SetTimeoutLengthForSession()
Const SessionTimeOutLengthInMinutes As Integer = 60
Session.Timeout = SessionTimeOutLengthInMinutes
End Sub

Private Sub InitializeComponent()
End Sub

Private Sub SetUpPageData()
Const MethodName As String = "SetUpPageData"
Dim mstdbConnection As SqlConnection
Dim Myreader As SqlDataReader

Try
mstdbConnection = New
SqlConnection(ConfigurationSettings.AppSettings("DBConnection"))
mstdbConnection.Open()

Dim mstDataCommand As New SqlCommand("stpr_MasterData",
mstdbConnection)
mstDataCommand.CommandType = CommandType.StoredProcedure

Myreader = mstDataCommand.ExecuteReader()
If Myreader.Read() Then

'Contol display of titles, notes and navigation buttons

SurveyNum = CInt(Myreader("SurveyID"))

' These are stored as public vars in the global module
Title = CStr(Myreader("TitleName"))
TotalQuestions = CInt(Myreader("TotalQuestions"))
Header = CStr(Myreader("Header"))
Footer = CStr(Myreader("Footer"))

'This is the first page so "Previous" button is not visible
imgbPrevious.Visible = False

lblTitle.Text = Title

If Trim(Header) <> "" Then
pnlParticipants.Visible = True
lblHeader.Visible = True
lblHeader.Text = Header
Else
pnlParticipants.Visible = False
lblHeader.Visible = False
End If
If Trim(Footer) <> "" Then
lblFooter.Visible = True
lblFooter.Text = Footer
Else
lblFooter.Visible = False
End If
End If

Catch ...
Finally... close reader and connection
End Try

setOnclickJScriptAttributeForHelpButton(imgbHelp)
End Sub

'Procedure to load and display each question and it's options for the
survey
Private Sub GetQuestion(ByVal SurveyNum As Integer, ByVal
CurrentQuestion As Integer)
Dim MyConnection As SqlConnection
Dim MyReader As SqlDataReader
Dim Param As SqlParameter
Dim MyCommand As SqlCommand
Dim QuestionText As String
Dim MyQuestion As Label = New Label
Dim QuestionCount As Integer
Const MethodName As String = "GetQuestion"

Try
MyConnection = New
SqlConnection(ConfigurationSettings.AppSettings("DBConnection"))
MyConnection.Open()

MyCommand = New SqlCommand("stpr_GetQuestion", MyConnection)
MyCommand.CommandType = CommandType.StoredProcedure

'load stored procedure parameters
Param = New SqlParameter("@SurveyID", SqlDbType.Int)
Param.Value = SurveyNum
MyCommand.Parameters.Add(Param)

Param = New SqlParameter("@QuestionNum", SqlDbType.Int)
Param.Value = CurrentQuestion
MyCommand.Parameters.Add(Param)

MyReader = MyCommand.ExecuteReader()
Do While MyReader.Read
QuestionCount += 1
Loop
MyReader.Close()
MyReader = MyCommand.ExecuteReader()

'Paint the current question number on the pages question counter
lblQuestionNum.Text = "Question " & CStr(CurrentQuestion) & " of
" & _
CStr(TotalQuestions)

If MyReader.Read Then

'Get the current question and type from the table
'set the public variables for it
QuestionText = CStr(MyReader("QuestionText"))
QuestionTypeID = CInt(MyReader("TypeID"))

'Paint the question on the page
MyQuestion.Text = CStr(CurrentQuestion) & ". " & QuestionText
MyQuestion.ToolTip = "Question " & MyQuestion.Text
pnlBoard.Controls.Add(MyQuestion)
pnlBoard.Controls.Add(New LiteralControl("<br>"))
pnlBoard.Controls.Add(New LiteralControl("<br>"))

'What type of options are to be displayed?
'Load controls from options table data

Select Case MyReader("TypeID")
Case 1
Dim myROptions As RadioButtonList = New
RadioButtonList
myROptions.Items.Add("Yes")
myROptions.Items.Add("No")
myROptions.ToolTip = MyQuestion.Text & ". Yes or No."
myROptions.ID = "myOpt"
pnlBoard.Controls.Add(myROptions)
Case 2
Dim myROptions As RadioButtonList = New
RadioButtonList
myROptions.Items.Add(CStr(MyReader("ChoiceText")))
Do While MyReader.Read 'read rest
myROptions.Items.Add(CStr(MyReader("ChoiceText")))
Loop
myROptions.ID = "myOpt"
pnlBoard.Controls.Add(myROptions)
Case 3
Dim myCOptions As CheckBoxList = New CheckBoxList
myCOptions.Items.Add(CStr(MyReader("ChoiceText")))
Do While MyReader.Read 'read rest
myCOptions.Items.Add(CStr(MyReader("ChoiceText")))
Loop
myCOptions.ID = "myOpt"
pnlBoard.Controls.Add(myCOptions)
Case 4
Dim myCommentText As TextBox = New TextBox
myCommentText.ToolTip = MyQuestion.Text
myCommentText.Width = New Unit(400)
myCommentText.Rows = 5
mycommenttext.TextMode = TextBoxMode.MultiLine
myCommentText.Text = " "
myCommentText.ID = "myComment"
pnlBoard.Controls.Add(myCommentText)
Case 5
Dim myTable As HtmlTable = New HtmlTable
Dim myHeader As Label = New Label
Dim myLOptions As Label
Dim row As HtmlTableRow
Dim cell As HtmlTableCell
Dim x, y As Integer
myTable.CellPadding = 3
' Get the number of rows and columns.
Dim numrows As Integer = 4
Dim numcells As Integer = 3
' Create a new row and add it to the Rows collection.
' Create the 3 header cells now.
' This is the Heading section of the table.
row = New HtmlTableRow
For x = 1 To 3 'only the columns required for
this typeID
cell = New HtmlTableCell
If x = 2 Then
cell.Controls.Add(New LiteralControl("From"))
ElseIf x = 3 Then
cell.Controls.Add(New LiteralControl("To"))
Else
myHeader.Text = " "
End If
row.Cells.Add(cell)

Next x
myTable.ID = "myTable"
myTable.Rows.Add(row)
'Start 1st working row and cell of options now
row = New HtmlTableRow
cell = New HtmlTableCell
myLOptions = New Label
myLoptions.Text = CStr(MyReader("ChoiceText"))
cell.Controls.Add(myLOptions)
row.Cells.Add(cell)

Dim Answer_1 As TextBox = New TextBox
Answer_1.Width = New Unit("100px")
Answer_1.ToolTip = CStr(MyReader("ChoiceText")) & "
From"
Answer_1.Text = " "
cell = New HtmlTableCell
cell.Controls.Add(Answer_1)
row.Cells.Add(cell)

Dim Answer_2 As TextBox = New TextBox
Answer_2.Width = New Unit("100px")
Answer_2.ToolTip = CStr(MyReader("ChoiceText")) & "
To"
Answer_2.Text = " "
cell = New HtmlTableCell
cell.Controls.Add(Answer_2)
row.Cells.Add(cell)

myTable.Rows.Add(row)

' Now iterate through rest of options to add rows as
needed.
Do While MyReader.Read
row = New HtmlTableRow
cell = New HtmlTableCell

myLOptions = New Label
myLOptions.Text = CStr(MyReader("ChoiceText"))
cell.Controls.Add(myLOptions)
row.Cells.Add(cell)

Answer_1 = New TextBox
Answer_1.Width = New Unit("100px")
Answer_1.ToolTip = CStr(MyReader("ChoiceText"))
& " From"
Answer_1.Text = " "
cell = New HtmlTableCell
cell.Controls.Add(Answer_1)
row.Cells.Add(cell)

Answer_2 = New TextBox
Answer_2.Width = New Unit("100px")
Answer_2.ToolTip = CStr(MyReader("ChoiceText"))
& " To"
Answer_2.Text = " "
cell = New HtmlTableCell
cell.Controls.Add(Answer_2)
row.Cells.Add(cell)

myTable.Rows.Add(row)
Loop
pnlBoard.Controls.Add(myTable)

Case 6
Dim myROptions As RadioButtonList = New
RadioButtonList
myROptions.Items.Add(CStr(MyReader("ChoiceText")))
Do While MyReader.Read 'read rest
myROptions.Items.Add(CStr(MyReader("ChoiceText")))
Loop
myROptions.SelectedIndex = 0
pnlBoard.Controls.Add(myROptions)
myROptions.ID = "myOpt"

Dim myCommentText As TextBox = New TextBox
myCommentText.Width = New Unit(400)
myCommenttext.TextMode = TextBoxMode.MultiLine
myCommentText.Rows = 4
myCommentText.ToolTip = "Enter additional comment"
myCommentText.Text = " "
myCommentText.ID = "myComment"
pnlBoard.Controls.Add(myCommentText)

Case 7
Dim myCOptions As CheckBoxList = New CheckBoxList
myCOptions.Items.Add(CStr(MyReader("ChoiceText")))
Do While MyReader.Read 'read rest
myCOptions.Items.Add(CStr(MyReader("ChoiceText")))
Loop
pnlBoard.Controls.Add(myCOptions)
myCOptions.ID = "myOpt"

Dim myCommentText As TextBox = New TextBox
myCommentText.Width = New Unit(400)
myCommenttext.TextMode = TextBoxMode.MultiLine
myCommentText.Rows = 4
myCommenttext.Text = " "
myCommentText.ToolTip = "Enter additional comment"
myCommentText.ID = "myComment"
pnlBoard.Controls.Add(myCommentText)
Case Else
'Raise an error here...bj
End Select
End If

Catch ...
Finally ... close reader and connection
End Try
End Sub

' Process the next button click event
' The next button has a final event that calls the final "Thank you" page.
Private Sub imgbNext_Click(ByVal sender As System.Object, _
ByVal e As System.Web.UI.ImageClickEventArgs) _
Handles imgbNext.Click
CurrentQuestion += 1
If CurrentQuestion > TotalQuestions Then
Server.Transfer("FinalPage.aspx")
End If
If CurrentQuestion = TotalQuestions Then
imgbNext.ImageUrl = "Images\button_Finish_F.gif"
imgbNext.ToolTip = "Finish"
End If
If CurrentQuestion > 1 Then
imgbPrevious.Visible = True
End If

If DataChanged() Then
SaveResult()
End If

GetQuestion(SurveyNum, CurrentQuestion) 'Paint question and answer
options on page.
End Sub

' Process the previous button click event
Private Sub imgbPrevious_Click(ByVal sender As System.Object, _
ByVal e As
System.Web.UI.ImageClickEventArgs) _
Handles imgbPrevious.Click
CurrentQuestion -= 1
If CurrentQuestion <= 1 Then
CurrentQuestion = 1
imgbPrevious.Visible = False
End If
If CurrentQuestion > 1 Then
imgbPrevious.Visible = True
imgbNext.Visible = True
End If
If imgbNext.ToolTip = "Finish" Then
imgbNext.ImageUrl = "Images\button_Next_N.gif"
imgbNext.ToolTip = "Next question"
End If

If DataChanged() Then
SaveResult()
End If

GetQuestion(SurveyNum, CurrentQuestion) 'Paint question and answer
options on page.
End Sub

Private Function DataChanged() As Boolean
Select Case QuestionTypeID
Case 1, 2, 6
Dim dmyROpt As RadioButtonList
dmyROpt = CType(pnlBoard.FindControl("myOpt"),
RadioButtonList)
If myROptions.SelectedIndex > -1 Then
DataChanged = True
End If
Case 3, 7
Dim dmyCOpt As CheckBoxList
dmyCOpt = CType(pnlBoard.FindControl("myOpt"), CheckBoxList)
If dmyCOpt.SelectedIndex > -1 Then
DataChanged = True
End If
Case 4
Dim dmyTOpt As TextBox
dmyTOpt = CType(pnlBoard.FindControl("myComment"), TextBox)
If Trim(dmyTOpt.Text) <> "" Then
DataChanged = True
End If
Case 5
Dim tb As Table
Dim tr As TableRow
tb = CType(pnlBoard.FindControl("myTable"), Table)
'go thru rows......
For Each tr In tb.Rows
DataChanged = Trim(tr.Cells(1).Text) <> ""
If DataChanged Then
Exit For
End If
Next tr
Case Else
'Raise an error here...bj
End Select
End Function

'Write the answers to the result table.
'Create the input parameters and write using stored procedures.
Private Sub SaveResult()
Dim MyConnection As SqlConnection
Dim Param As SqlParameter
Dim MyCommand As SqlCommand
Dim methodname As String = "Next Button"

Try
MyConnection = New
SqlConnection(ConfigurationSettings.AppSettings("DBConnection"))
MyConnection.Open()

MyCommand = New SqlCommand("stpr_SURVEY_DUI_Results",
MyConnection)
MyCommand.CommandType = CommandType.StoredProcedure

Select Case QuestionTypeID
Case 1
'Yes-No type
Dim dmyOpt As RadioButtonList
dmyOpt = CType(pnlBoard.FindControl("myOpt"),
RadioButtonList)

Param = New SqlParameter("@ChoiceNum", SqlDbType.Int)
Param.Value = dmyOpt.SelectedIndex
MyCommand.Parameters.Add(Param)
Param = New SqlParameter("@Answer1", SqlDbType.VarChar)
Param.Value = dmyOpt.SelectedItem.Text
MyCommand.Parameters.Add(Param)
Param = New SqlParameter("@Answer2", SqlDbType.VarChar)
Param.Value = ""
MyCommand.Parameters.Add(Param)
Param = New SqlParameter("@NA", SqlDbType.Bit)
Param.Value = (dmyOpt.SelectedIndex > -1)
MyCommand.Parameters.Add(Param)
Param = New SqlParameter("@CommentText", SqlDbType.Text)
Param.Value = ""
MyCommand.Parameters.Add(Param)
Case 2
'Single-Select type
Dim dmyOpt As RadioButtonList
dmyOpt = CType(pnlBoard.FindControl("myOpt"),
RadioButtonList)
Param = New SqlParameter("@ChoiceNum", SqlDbType.Int)
Param.Value = dmyOpt.SelectedIndex
MyCommand.Parameters.Add(Param)
Param = New SqlParameter("@Answer1", SqlDbType.VarChar)
Param.Value = dmyOpt.SelectedItem.Text
MyCommand.Parameters.Add(Param)
Param = New SqlParameter("@Answer2", SqlDbType.VarChar)
Param.Value = ""
MyCommand.Parameters.Add(Param)
Param = New SqlParameter("@NA", SqlDbType.Bit)
Param.Value = (dmyOpt.SelectedIndex > -1)
MyCommand.Parameters.Add(Param)
Param = New SqlParameter("@CommentText", SqlDbType.Text)
Param.Value = ""
MyCommand.Parameters.Add(Param)
Case 3
'Multi-select type
Dim dmyOpt As CheckBoxList
dmyOpt = CType(pnlBoard.FindControl("myOpt"),
CheckBoxList)
Dim dmyComment As TextBox
dmyComment = CType(pnlBoard.FindControl("mycomment"),
TextBox)

Dim item As ListItem
For Each item In dmyOpt.Items

'must process each selected item
If item.Selected Then
'load stored procedure parameters
Param = New SqlParameter("@SurveyID",
SqlDbType.Int)
Param.Value = SurveyNum
MyCommand.Parameters.Add(Param)
Param = New SqlParameter("@QuestionNum",
SqlDbType.Int)
Param.Value = CurrentQuestion
MyCommand.Parameters.Add(Param)
Param = New SqlParameter("@ChoiceNum",
SqlDbType.Int)
Param.Value = dmyOpt.SelectedIndex
MyCommand.Parameters.Add(Param)
Param = New SqlParameter("@Answer1",
SqlDbType.VarChar)
Param.Value = dmyOpt.SelectedItem.Text
MyCommand.Parameters.Add(Param)
Param = New SqlParameter("@Answer2",
SqlDbType.VarChar)
Param.Value = ""
MyCommand.Parameters.Add(Param)
Param = New SqlParameter("@NA", SqlDbType.Bit)
Param.Value = 0
MyCommand.Parameters.Add(Param)
Param = New SqlParameter("@CommentText",
SqlDbType.Text)
Param.Value = ""
MyCommand.Parameters.Add(Param)
Param = New SqlParameter("@CreUser",
SqlDbType.VarChar)
Param.Value = CreateUserID
MyCommand.Parameters.Add(Param)
MyCommand.ExecuteNonQuery()
End If
Next item
Case 4
'Text Box only type
Dim dmyComment As TextBox
dmyComment = CType(pnlBoard.FindControl("mycomment"),
TextBox)
Param = New SqlParameter("@ChoiceNum", SqlDbType.Int)
Param.Value = ""
MyCommand.Parameters.Add(Param)
Param = New SqlParameter("@Answer1", SqlDbType.VarChar)
Param.Value = ""
MyCommand.Parameters.Add(Param)
Param = New SqlParameter("@Answer2", SqlDbType.VarChar)
Param.Value = ""
MyCommand.Parameters.Add(Param)
Param = New SqlParameter("@NA", SqlDbType.Bit)
Param.Value = (Trim(dmyComment.Text) = "")
MyCommand.Parameters.Add(Param)
Param = New SqlParameter("@CommentText", SqlDbType.Text)
Param.Value = dmycomment.Text
MyCommand.Parameters.Add(Param)
Case 5...
rest of cases...
Case Else
'oops what happend!
End Select

If QuestionTypeID <> 3 And QuestionTypeID <> 5 And
QuestionTypeID <> 7 Then
'otherwise already processed
'load rest of stored procedure parameters
Param = New SqlParameter("@SurveyID", SqlDbType.Int)
Param.Value = SurveyNum
MyCommand.Parameters.Add(Param)

Param = New SqlParameter("@QuestionNum", SqlDbType.Int)
Param.Value = CurrentQuestion
MyCommand.Parameters.Add(Param)
Param = New SqlParameter("@CreUser", SqlDbType.VarChar)
Param.Value = CreateUserID
MyCommand.Parameters.Add(Param)
'save data now
MyCommand.ExecuteNonQuery()
End If
Catch ...
Finally... close connection
End Try
End Sub
End Class
 
K

Karl Seguin

Bass:
I think the problem is as simple as not specifying the CurrentQuestion on
postback.

When you postback, you recreate the control via your call to
GetQuestion(SurveyNum, CurrentQuestion) in the ELSE of the page_load...but
CurrentQuestion isn't initialized hence it's passing in 0. That can be my
only guess.


A couple side notes, turning option strict on in vb.net would be greatly
beneficial for you, although difficult at first. Can't find a link right
now...but if you right-click the project in VS.Net it'll be an option there
(somewhere).

Also, how you ge the data could be made much more efficient. I take it your
stpr_MasterData gets all the questions, which you loop through to get a
total count, and make sure the current question is always the first. It's
inneficient because (a) you are returning all questions (even though you
only need the first) and (b) you are hitting the DB multiple times.

2 ways to solve this...
use a datatable and cache it (i'll let you explore this on your own)
make your sproc return 2 result sets

create procedure stpr_MasterData
@CurrentQuestion INT
AS
BEGIn
SELECT Count(*) from MyQuestions

-- sELECT * sucks, but just for a demo...
SELECT * FROM MyQuestions
end


then ur vb.net code can look like:

MyReader = MyCommand.ExecuteReader()
if MyReader.Read then
QuestionCount = cint(MyReader(0))
end if

MyReader.NextResult 'jumps to the 2nd select

if MyReader.Read Then
'do your other stuff here
End if



Btw, why call them "MyXXXX" who elses could they be?? :)

Karl

--
MY ASP.Net tutorials
http://www.openmymind.net/ - New and Improved (yes, the popup is annoying)
http://www.openmymind.net/faq.aspx - unofficial newsgroup FAQ (more to
come!)


Bass Pro said:
Hi Karl,

This is my code....
I didn't think there was a postback until after the button click event was
completed. Am I wrong in my thinking? New to asp.net so I'm at your
mercy...tks Bill

Imports System.Data.SqlClient
Imports System.Text.RegularExpressions
Imports Surveys.SurveysLibrary
Imports Surveys.CCExceptionLog
Imports System.Web.UI
Imports System.Web.UI.WebControls
Imports System.Web.UI.HtmlControls

Public Class Main
Inherits System.Web.UI.Page
Protected WithEvents lblFooter As System.Web.UI.WebControls.Label

.....
 
G

Guest

Hi Karl,
Txs.... This will help me a lot. I've got to get this thing off the
ground today.

(myXXX).. LOL habit I guess....

Again txs.
Bill
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,772
Messages
2,569,593
Members
45,111
Latest member
VetaMcRae
Top