How can i put multiple data in one datagrid cell? For example, a user can be a member of different organisations.
But i dont want the table to create a new datagrid row for the same user that is a member of multiple organisations.
This is how the code looks like right now:
Dim dSourceMemberOf As New SqlDataAdapter("QUERY", dbConn)
This fills the datagrid, but for some users there are more then 5 rows. So i'd like to put for one particular column all data in one cell.
How can this be done?
Edit:
This is how it woud look like right now:
username memberof
user1 dft
user1 kbo
user2 test
And this is how i want it to looke like:
username memberof
user1 dft
kbo
user2 test
I think the best solution is to group the data using a Linq query, then bind the grouped data to a gridview:
So the GridView would look like this:
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False">
<Columns>
<asp:BoundField DataField="UserName" />
<asp:TemplateField>
<ItemTemplate>
<asp:ListBox ID="lst" runat="server" DataSource="<%# Container.DataItem.MemberOfGrouped %>" DataTextField="MemberOf"></asp:ListBox>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
and here is some example code to populate it:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim UngroupedData As List(Of YourData) = New List(Of YourData)()
Dim item1 As YourData = New YourData()
item1.MemberOf = "dft"
item1.UserName = "user1"
UngroupedData.Add(item1)
Dim item2 As YourData = New YourData()
item2.MemberOf = "kbo"
item2.UserName = "user1"
UngroupedData.Add(item2)
Dim grouped = From u In UngroupedData Group u By Key = u.UserName Into Group _
Select UserName = Key, MemberOfGrouped = Group.ToList()
GridView1.DataSource = grouped
GridView1.DataBind()
End Sub
Public Class YourData
Private _userName As String
Public Property UserName() As String
Get
Return _userName
End Get
Set(ByVal value As String)
_userName = value
End Set
End Property
Private _memberOf As String
Public Property MemberOf() As String
Get
Return _memberOf
End Get
Set(ByVal value As String)
_memberOf = value
End Set
End Property
End Class
Sorry, I think on paint was wrong, concept was right though - looks like you need to do it on the databind event event... more here (first three links will show you how to do what you require I think) - you could look at the row you are on, get the previous row, then decide what to do with a cell in your current row based on the prev row
You could use a table inside the GridView-Cell (or a Listbox like Ross Scott suggested).
<ItemTemplate>
<asp:table id="TblUserGroups" runat="server" Height="100%" Width="100%" CellSpacing="0" CellPadding="0">
</asp:table>
</ItemTemplate>
and in RowDataBound of gridview(ItemDataBound of Datagrid works similar):
Protected Sub Gridview1_RowDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles Gridview1.RowDataBound
Select Case e.Row.RowType
Case DataControlRowType.DataRow
Dim drUser As DataRowView = DirectCast(e.Row.DataItem, DataRowView)
Dim TblUserGroups As Table = DirectCast(e.Row.FindControl("TblUserGroups"), Table)
Dim userID as int32 = Ctype(drUser(0), Int32)
Dim tblGroups as DataTable = getTblUserGroups(userID) 'write a function that returns the Groups of a given User f.e. as DataTable'
If tblGroups.Rows.Count = 0 Then
Dim tr As New TableRow
Dim td As New TableCell
Dim LblNoGroup As New Label
LblNoGroup .Text = "no user-group"
td.CssClass = "UserWithoutGroup"
td.Controls.Add(LblNoGroup)
tr.Cells.Add(td)
TblUserGroups.Rows.Add(tr)
Else
For Each groupRow As DataRow In tblGroups.Rows
Dim tr As New TableRow
Dim td As New TableCell
Dim LblGroup As New Label
LblGroup.Text = groupRow("GroupName").ToString 'The groups name column'
td.Controls.Add(LblGroup)
tr.Cells.Add(td)
TblUserGroups.Rows.Add(tr)
Next
End If
End Select
End Sub
I think this is the most flexible way.
Related
I am stuck into a asp.net use case where a listbox(id:l1) is getting populated from a query which returns say 3 columns(name, id, value), now the id is assigned to l1.datavaluefield="id" , but i want to store the value of name in a string variable based on which ever item I click on the listbox. How do i do this please help
I have no idea at all.
Well, it does not really matter if the query returns 3 columns, or 10 columns.
The list box only has provisions for 2 columns. So, in most cases, you store the "value" as the database "ID" column, and then you have a column for display of the 2nd column.
To get "other" columns - ones not included in the listbox?
you as a genreal rule have to use the "ID" and re-pull (use anohter query) to get those other columns.
So, say we have a list box, it will display ID, and HotelName (2 columns). it really does not matter if you feed the listbox 5 or 10 columns, it will still only use + store + have the 2 columns.
So, lets setup a list box, and when you click on the given hotel, we will display other columns from that table on the web page.
So, this list box, and a bit more to display the other columns:
<h4>Select Hotel</h4>
<asp:ListBox ID="ListBox1" runat="server"
DataValueField="ID"
DataTextField="HotelName"
AutoPostBack="true"
OnSelectedIndexChanged="ListBox1_SelectedIndexChanged" Height="162px" Width="308px" >
</asp:ListBox>
<br />
<h4>Hotel Informaton</h4>
<div style="width: 303px; height: 185px;">
<div style="text-align: right">
HotelName: <asp:TextBox ID="txtHotel" runat="server"></asp:TextBox> <br />
City: <asp:TextBox ID="txtCity" runat="server"></asp:TextBox>
</div>
Descripiton:
<br />
<asp:TextBox ID="txtDesc" runat="server" TextMode="MultiLine" Height="83px" Width="290px"></asp:TextBox>
</div>
And our code behind is this:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
LoadData
End If
End Sub
Sub Loaddata()
Dim strSQL As string =
"SELECT ID, HotelName FROM tblHotelsA
ORDER BY HotelName"
Dim cmdSQL As New SqlCommand(strSQL)
ListBox1.DataSource = MyrstP(cmdSQL)
ListBox1.DataBind()
End Sub
Protected Sub ListBox1_SelectedIndexChanged(sender As Object, e As EventArgs)
Dim PKID As Integer = ListBox1.SelectedItem.Value
Dim cmdSQL As New SqlCommand("SELECT * FROM tblHotelsA WHERE ID = #ID")
cmdSQL.Parameters.Add("#ID", SqlDbType.Int).Value = PKID
Dim rstData As DataTable = MyrstP(cmdSQL)
With rstData.Rows(0)
txtHotel.Text = .Item("HotelName")
txtCity.Text = .Item("City")
txtDesc.Text = .Item("Description")
End With
End Sub
Public Function MyrstP(cmdSQL As SqlCommand) As DataTable
Dim rstData As New DataTable
Using mycon As New SqlConnection(GetConstr)
Using (cmdSQL)
cmdSQL.Connection = mycon
mycon.Open()
rstData.Load(cmdSQL.ExecuteReader)
End Using
End Using
Return rstData
End Function
And now we get/see this:
So, note how we are free to get/use/have ANY column from the database. However, since the listbox ONLY holds those two columns, then we have to hit the database again based on the LB selecting, pull the additional columns, and at that point we are free to use/have/enjoy use of all database columns, not just the ones used in the bl
My end goal is for my program to work like this:
Press Edit button on GridView
RowEditing event triggers, creating a new window
New window with a DetailsView displays the full information.
I got all that to work, however, the DetailsView only displays the content from the first entry in the database table, instead of the entry which I pressed the edit button on.
So my question is, how can I tell the program which row is being edited on the GridView, and get the information(like the key) to make a new select statement on the DetailsView?
TablePage.aspx(with only the relevant code)
<asp:GridView ID="GridView1" runat="server" OnRowEditing="RowEditing"
AutoGenerateEditButton="True">
<Columns>
<asp:BoundField DataField="name" HeaderText="name" SortExpression="name" />
</Columns>
</asp:GridView>
TablePage.aspx.vb(again, only relevant code)
Protected Sub RowEditing(ByVal sender As Object, ByVal e As GridViewEditEventArgs)
Dim url As String = "/tables/edit.aspx"
Dim s As String = "window.open('" & url + "', 'popup_window', 'width=300,height=300s,left=100,top=100,resizable=yes');"
ClientScript.RegisterStartupScript(Me.GetType(), "script", s, True)
End Sub
You can use e.NewEditIndex from RowEditing function to get the current row edited in GridView, obtaining that you can access the row and get any cell text from the row.
Please try this:
Protected Sub RowEditing(ByVal sender As Object, ByVal e As GridViewEditEventArgs)
'First, get the current RowIndex
Dim selectedRowIndex As Integer = e.NewEditIndex
'Then get any information you need from the row, for example the name of the first cell
Dim selectedItemText As String = GridView1.Rows(selectedRowIndex).Cells(1).Text
'Now you can store the information in session to use it in other page
Session("EditParameter") = selectedItemText
Dim url As String = "/tables/edit.aspx"
Dim s As String = "window.open('" & url + "', 'popup_window', 'width=300,height=300s,left=100,top=100,resizable=yes');"
ClientScript.RegisterStartupScript(Me.GetType(), "script", s, True)
End Sub
Of course you can add another hidden bound field that contains the record number and then access it instead of the name.
Hope this helps.
Trying to use data binding between a list of objects and a data list control. What I want to do are
create the list of objects
have them bound to the controls
change data in the UI
have the changes in the ui bound to the list of objects
on post back - have the list of objects with the new values from the ui
<body>
<form id="form1" runat="server">
<div>
<asp:DataList ID="DataList1" runat="server" DataKeyField="ClassID" ViewStateMode="Enabled">
<ItemTemplate>
<asp:TextBox ID="txtValue1" runat="server" Text='<%# Bind("Value1") %>'></asp:TextBox>
<asp:TextBox ID="txtValue2" runat="server" Text='<%# Bind("Value2") %>'></asp:TextBox>
<asp:TextBox ID="txtvalue3" runat="server" Text='<%# Bind("Value3") %>'></asp:TextBox>
</ItemTemplate>
</asp:DataList>
<asp:Button ID="btnDoPostBack" runat="server" Text="Do Post Back" />
</div>
</form>
</body>
Option Explicit On
Option Strict On
Imports System.Diagnostics
Partial Class _Default
Inherits System.Web.UI.Page
Dim Class1List As List(Of Class1)
Protected Sub Page_PreLoad(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.PreLoad
Dim txtValue1 As TextBox
Dim txtValue2 As TextBox
Dim txtValue3 As TextBox
Dim ItemIndex As Integer = 0
If Page.IsPostBack Then
Class1List = CType(Session("Class1List"), List(Of Global.Class1))
'Class1List = CType(DataList1.DataSource, List(Of Global.Class1))
For Each myDataListItem As DataListItem In DataList1.Items
txtValue1 = CType(myDataListItem.FindControl("txtValue1"), TextBox)
Long.TryParse(txtValue1.Text, Class1List(ItemIndex).Value1)
txtValue2 = CType(myDataListItem.FindControl("txtValue2"), TextBox)
Integer.TryParse(txtValue2.Text, Class1List(ItemIndex).Value2)
txtValue3 = CType(myDataListItem.FindControl("txtValue3"), TextBox)
Class1List(ItemIndex).Value3 = txtValue3.Text
ItemIndex += 1
Next
End If
End Sub
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim myClass1 As Class1
If Not Page.IsPostBack Then
Class1List = New List(Of Class1)
myClass1 = New Class1
Class1List.Add(myClass1)
BindData()
Else
'Class1List = CType(DataList1.DataSource, List(Of Global.Class1))
Debug.WriteLine("Page_Load, Value1 = " & Class1List(0).Value1.ToString())
Debug.WriteLine("Page_Load, Value2 = " & Class1List(0).Value2.ToString())
Debug.WriteLine("Page_Load, Value3 = " & Class1List(0).Value3)
End If
End Sub
Protected Sub Page_Unload(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Unload
Session("Class1List") = Class1List
End Sub
Sub BindData()
DataList1.DataSource = Class1List
DataList1.DataBind()
End Sub
Protected Sub DataList1_ItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.DataListItemEventArgs) Handles DataList1.ItemDataBound
Dim myClass1 As Class1
If e.Item.ItemType = ListItemType.Item OrElse e.Item.ItemType = ListItemType.AlternatingItem Then
myClass1 = CType(e.Item.DataItem, Class1)
Debug.WriteLine("DataList1_ItemDataBound, Value1 = " & myClass1.Value1.ToString())
Debug.WriteLine("DataList1_ItemDataBound, Value2 = " & myClass1.Value2.ToString())
Debug.WriteLine("DataList1_ItemDataBound, Value3 = " & myClass1.Value3)
End If
End Sub
Protected Sub btnDoPostBack_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnDoPostBack.Click
Dim myRandom As New Random
Class1List(0).Value1 = myRandom.Next(100)
Class1List(0).Value2 = myRandom.Next(100)
Class1List(0).Value3 = myRandom.Next(100).ToString()
Debug.WriteLine("btnDoPostBack_Click, Value1 = " & Class1List(0).Value1.ToString())
Debug.WriteLine("btnDoPostBack_Click, Value2 = " & Class1List(0).Value2.ToString())
Debug.WriteLine("btnDoPostBack_Click, Value3 = " & Class1List(0).Value3)
BindData()
End Sub
End Class
The Class Class1 is trivial:
Option Explicit On
Option Strict On
Imports Microsoft.VisualBasic
Public Class Class1
Private _ClassID As Long
Private _Value1 As Long
Private _Value2 As Integer
Private _value3 As String = String.Empty
Public Property ClassID As Long
Get
Return _ClassID
End Get
Set(ByVal value As Long)
_ClassID = value
End Set
End Property
Public Property Value1 As Long
Get
Return _Value1
End Get
Set(ByVal value As Long)
_Value1 = value
End Set
End Property
Public Property Value2 As Integer
Get
Return _Value2
End Get
Set(ByVal value As Integer)
_Value2 = value
End Set
End Property
Public Property Value3 As String
Get
Return _value3
End Get
Set(ByVal value As String)
_value3 = value
End Set
End Property
End Class
Update: I got the code behind above to do what I want it to do - I was thinking there was a better way?
You didn't show your databinding "Load" phase (the code which binds the data from the list to the controls)--so I assume the part you are unhappy with is the "Save" phase (the code in Page_PreLoad which binds the modified values from the controls back to the list), i.e. #4 in your list:
have the changes in the ui bound to the list of objects
It sounds like you want "two-way Data Binding": you want .NET to update your model as easily as it reads from your model. This is a common complaint. One solution is to subclass WebControl, but that's a mess.
You are already using the <%# Bind("...") %> syntax, so you have the right idea. That approach should work out-of-the-box with <asp:SqlDataSource>, but you want to update a custom class, so you need to use <asp:ObjectDataSource> instead. Use the approach in this article, except with ObjectDataSource instead of SqlDataSource.
But first you have to make your model (i.e., Class1) compatible with ObjectDataSource by marking it with [System.ComponentModel.DataObject] and designating the appropriate update method like this:
[System.ComponentModel.DataObjectMethodAttribute(
System.ComponentModel.DataObjectMethodType.Update, true)]
public bool UpdateProduct(string productName, ...) {
...
}
This would allow you to use an ObjectDataSource on your webform and finally get nice 2-way databinding. Read the links to for full details.
Visual Studio offers various clunky ways of automating this, such as TableAdapters and the infamous Strongly-Typed DataSet (STD), but those don't help people like yourself who have their own object model. I don't recommend STDs anyway.
I was thinking there was a better way?
I don't think your current approach is bad. If you're worried about having tons of logic in your webforms, you would gain much more by using an MVC approach than worrying about binding sugar...
I have the following code in my codebehind Page_Load function that sets the default selected value of a dropdownlist in detailsview based on the name of a record returned from a sql data query.
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Me.Page.Title = "Editing record"
'Perform dropdown list population operations
Dim myDDL As DropDownList = DetailsView1.FindControl("reqCategoryDropDown")
If Page.IsPostBack = False Then
Dim ticket_ID As String = getDataKey(DetailsView1)
'Fetch Category ID
Dim sqlText As String = "SELECT TS_REQCATEGORY FROM USR_ITFAC WHERE (TS_ID = " + ticket_ID + ") "
Dim reqDataReader As SqlDataReader = GetDataReader(sqlText)
reqDataReader.Read()
Dim category_ID As String = reqDataReader(0)
'Fetch Category name and set as selected value in dropdown list
sqlText = "SELECT TS_NAME FROM TS_SELECTIONS WHERE (TS_ID = " + category_ID + ") "
reqDataReader = GetDataReader(sqlText)
reqDataReader.Read()
category_Name = reqDataReader(0)
'myDDL.DataBind()
myDDL.SelectedValue = category_Name
End If
End Sub
My problem is that when the page loads for the first time, even though I set the selected value for the dropdownlist it will not display and instead simply displays the default first name in my dropdownlist. I tried Binding my dropdownlist before and after I set the selectedvalue, it is commented out in the sample code above, but that didn't seem to do anything.
UPDATE:
I'm setting the data source in the webform as follows:
Dropdownlist:
<asp:DropDownList DataSourceID="ReqCategoryData" DataTextField="ReqCategory" DataValueField="ReqCategory"
ID="reqCategoryDropDown" runat="server" AppendDataBoundItems="true" AutoPostBack="true">
</asp:DropDownList>
Connects to data source a few lines down:
<asp:SqlDataSource ID="ReqCategoryData" runat="server" ConnectionString="<%$ ConnectionStrings:TTPRODReportsQuery %>"
SelectCommand="SELECT TS_NAME AS ReqCategory FROM dbo.TS_SELECTIONS WHERE (TS_FLDID = 5299 AND TS_STATUS = 0) ORDER BY TS_NAME">
</asp:SqlDataSource>
UPDATE_2:
Ok, so I implemented he SQLDataSource programmatically in the code-behind under the Page_Init function as follows:
Protected Sub Page_Init(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Init
DetailsView1.DefaultMode = DetailsViewMode.Edit
''Setup DropDownList SqlDataSource
ddlDataSource.ID = "ReqCategoryData"
Page.Controls.Add(ddlDataSource)
ddlDataSource.ConnectionString = ConfigurationManager.ConnectionStrings("TTPRODReportsQuery").ConnectionString
ddlDataSource.SelectCommand = "SELECT TS_NAME AS ReqCategory FROM dbo.TS_SELECTIONS WHERE (TS_FLDID = 5299 AND TS_STATUS = 0) ORDER BY TS_NAME"
Dim args As New DataSourceSelectArguments
ddlDataSource.Select(args)
ddlDataSource.DataBind()
End Sub
After which I set attempt to set the selected value of the dropdownlist as above. The page is still not setting the selected value.
Perhaps check these items:
ensure you're calling myDDL.DataSource = reqDataReader or some other form of setting the DataSource of your dropdownlist.
ensure the dropdownlist has its DataTextField and DataTextField set properly. This could be in code-behind or in markup.
The 0'th index of reqDataReader -- are you sure that's the intended ordinal for the DataValueField?
Perhaps something like this:
With myDDL
.DataTextField = "CategoryName"
.DataValueField = "CategoryID" ' or perhaps CategoryName as your value.
.DataSource = reqDataReader
.DataBind()
.SelectedValue = category_Name ' Name or ID; depends on what was set as DataValueField
End With
DataBinding - Code-Behind vs. Markup DataSources
Consider choosing one style of binding your dropdownlist - in code-behind or with a markup SqlDataSource. Having both generates confusion on which bind wins - the code-behind or the datasource. I think it's the SqlDataSource in this case.
Consider removing the SqlDataSource from out of the markup, and create a method in code-behind whose sole purpose is to create the data binding. This is the only place where the binding should happen. If you ever need to track down a defect or enhance your logic, it's the only one place to visit.
Private Sub BindMyDropDown(Optional ByVal selectedValue as String)
With myDDL
.DataTextField = "CategoryName"
.DataValueField = "CategoryID" ' or perhaps CategoryName as your value.
.DataSource = LoadTicketReqCategory(TicketID)
.DataBind()
.SelectedValue = selectedValue ' Name or ID; depends on what was set as DataValueField
End With
End Sub
From your Page_Load(), check for IsPostBack() and call this method when you aren't posting back.
myDDL.ClearSelection
item = myDDL.Items.FindByValue(category_Name)
item.selected = true
--
You could also try setting the SelectedIndex to 2, for example, to check it that way.
The problem might be that you are assigning the myDDL variable outside of the postback check.
Dim myDDL As DropDownList = DetailsView1.FindControl("reqCategoryDropDown")
If Page.IsPostBack = False Then
Should be
If Page.IsPostBack = False Then
Dim myDDL As DropDownList = DetailsView1.FindControl("reqCategoryDropDown")
Could anyone please enlighten me about how one might go about binding to a gridview in ASP.Net 4 in a scenario where the first row of my gridview should be the headers, the second should be a combobox for each column and the third is the beginning of my actual datasource.
If you can imagine what I am trying to achieve is an ability to create a binding between each column in the datagrid and another datasource. This binding is created by the user selecting a value in the comboboxes. However no matter what I try I cant seem to achieve this.
HeaderText1 | HeaderText2 | HeaderText3
ComboBox1 | ComboBox2 | ComboBox3
DataRow1 | DataRow1 | DataRow1
DataRow2 | DataRow2 | DataRow2
DataRow3 | DataRow3 | DataRow3
You can put a DropDownList into a Gridview column quite easily by using a TemplateColumn:
<asp:GridView runat="server" ID="ComboboxGridView">
<Columns>
<asp:TemplateField HeaderText="Column 1">
<HeaderTemplate>
<asp:DropDownList runat="server" ID="Column1DropDownList" />
</HeaderTemplate>
<ItemTemplate>
<asp:Label runat="server" ID="Column1DisplayLabel" Text='<%# Eval("Column1") %>' />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
and you can bind the DropDownList to another data source quite easily, especially you're using the DataSource controls. I'm not clear on what you're doing with the DropDownLists in the header though - is it for filtering the rows that appear in the GridView?
So for anyone curious this appears to be the solution to the problem.
Private Sub grdMainGrid_RowCreated(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles grdMainGrid.RowCreated
If e.Row.RowType = DataControlRowType.Header Then
For Each itm As TableCell In e.Row.Cells
itm.Text = GenerateHeaderHTML()
Next
End If
End Sub
PS: If anyone has any better solutions I would love to hear them :-)
The following is the code I have in the GenerateHeaderHTML(). My code is a very specific case (and prob far from great). However note that you can use any html you wish.
Private Sub grdMainGrid_RowCreated(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles grdMainGrid.RowCreated
If Me.BoundedObjects IsNot Nothing Then
If e.Row.RowType = DataControlRowType.Header Then
Dim PrimitivePropertyNames As List(Of String) = ParserHelper.GetPrimitivePropertyNames(Me.BoundedObjects.ToList)
Dim i As Integer = 0
For Each itm As TableCell In e.Row.Cells
itm.Text = ucStockImport.CreateBindingHeaderTable(itm.Text, PrimitivePropertyNames, i.ToString)
i += 1
Next
End If
Else
Throw New StockImportException("ucStockImport.BoundedObjects Is Nothing")
End If
End Sub
Private Shared Function CreateBindingHeaderTable(ByVal HeaderText As String, ByVal PropertyNames As List(Of String), ByVal ID As String) As String
Return String.Format("<table><tr><td>{0}</td></tr><tr><td>{1}</td></tr></table>", HeaderText, ucStockImport.CreateBindedObjectDropDownList(PropertyNames, ID))
End Function
Private Shared Function CreateBindedObjectDropDownList(ByVal PropertyNames As List(Of String), ByVal ID As String) As String
Dim strBuilder As New StringBuilder
strBuilder.Append(String.Format("<option value=""{0}"">{1}</option>", i, propName))
Dim i As Integer = 0
For Each propName As String In PropertyNames
strBuilder.Append(String.Format("<option value=""{0}"">", i) & propName & "</option>")
i += 1
Next
strBuilder.Append("</select>")
Return strBuilder.ToString
End Function