How to bind the selected value of a DropDownList - asp.net

Data binding is all about declarative code, right? So I specify what I want with attributes, and the framework takes care of the rest. Unless I'm mistaken and data binding relates to S&M, right?
So, why does the DropDownList control only provide binding fields for its data source, i.e. its list source, and not for its actual data field. i.e. how the heck to I bind the selected value my name DropDownList to the Name field in my Person record? Is this a gross oversight on Microsoft's part, or on mine?
What is the point of two way data binding if I still have to manually set and read the selected value?

You might want to do something like the code below.
You can not set the "SelectedValue" declaratively, but by saying
"SelectedValue=<%# [code here] %> you are effectively causing the value to be set when the control is data bound.
<asp:DropDownList
ID="DropDownInfoSource"
runat="server"
DataSourceID="_employeeDataSource"
DataTextField="EmployeeName"
DataValueField="EmployeeID"
SelectedValue='<%# Bind("EmployeeID") %>'
/>

I don't know if it will really help you, but did you tried to setup the "SelectedValue" on Code behind?
Example:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
DropDownInfoSource.SelectedValue = "1" ' your value, here
End Sub

There is a field where you define the datasource, the datatextfield (what shows up in the list) and the datavaluefield.
Example (I have a datatable with a column "EmployeeID" and a column "EmployeeName"):
dropdownlist1.datasource = DT
dropdownlist1.datatextfield = "EmployeeName"
dropdownlist1.datavaluefield = "EmployeeID"
dropdownlist1.databind()

Related

How to htmlencode body but not heading of gridview

I have a GridView. I want the content of the cells, the actual detail data, to be html-encoded. But I want to keep the raw HTML in the heading.
That is, the heading in this case is the name of a language and the ISO code, for example "English (EN)". I want the name and code on separate lines, so I'm specifying the heading as "English<br/>(EN)".
But for the content, I want to see any HTML. If it says "<p>foobar</p>" I want the p-tags to display.
If I say "htmlencode=false", then the heading doesn't get encoded, but neither does the data.
Is there any way to say, html-encode the data, but not the heading?
If it matters, I'm building the columns in code rather than with tags in the ASP file, depending on which languages I find in my data. So here's how I'm creating the column:
For Each row As DataRow In ds.Tables(0).Rows
Dim iso2 = row("language")
Dim name = row("name")
... other code ...
Dim head = String.Format("{0}<br/>({1})", name, iso2)
gvSnippets.Columns.Add(New BoundField With {.HeaderText = head, .DataField = iso2, .HtmlEncode = False})
... other code ...
End For
(My first draft did not set HtmlEncode.)
Curious observation: In my first couple of test runs, the data did not include any HTML or entities, and the HTML in the heading was NOT encoded, I got the line break and not "<br/>". Then I did a test where there were entities in the data and the entities got html-encoded ... and so did the header. So like, ASP is apparently saying that by default, if the data has no HTML but the heading does, then don't HTML-encode the heading. But if the data has HTML, then HTML-encode both the data and the heading. So like, it's deciding dynamically whether to html-encode the heading or not.
In reply to #fnostro, here's the markup for the GridView:
<asp:GridView ID="gvSnippets" runat="server" AutoGenerateColumns="False" SkinID="skin3" EmptyDataText="No records found" Visible="false">
</asp:GridView>
There is no <Columns> markup. I build the columns completely in code. I haven't tested if the same behavior occurs in what I assume is the more normal case where you specify columns with markup.
Add these lines of code to the beginning of your loop
row("language") = HttpUtility.HtmlEncode(dr("language"))
row("name") = HttpUtility.HtmlEncode(dr("name"))
Based on my reading of the information provided in your post I have the following suggestions:
You should isolate data formatting from raw data.
Your DataTable is the data source for the GridView. The DataTable should contain only raw data, completely unformatted and unadulterated.
The DataTable gets bound to the Gridview by setting the GridView DataSource and making a call to DataBind(). Calling gvSnippets.Databind() will trigger all the databinding events associated with Gridviews which will allow you to:
Manage simple formatting and binding in the GridView Columns in the aspx markup.
Handle more complicated formatting in the code behind for specific GridView events like the RowDataBound event.
Regarding the GridView Header: HeaderText appears once at the top of the Gridview and is stored internally in GridView.HeaderRow, not on a per row basis even though every bound field has a HeaderText property.
Example excerpt gvSnippets Markup per your update:
<asp:GridView ID="gvSnippets" runat="server"
AutoGenerateColumns="False" SkinID="skin3"
EmptyDataText="No records found" Visible="false">
</asp:GridView>
Then you can do things like this in the Code Behind:
Public Class __JunkWebForm1
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
' Fill Dataset first, then:
gvSnippets.DataSource = ds.Tables(0)
' Add Columns...
gvSnippets.Columns.Add(...)
gvSnippets.Columns.Add(...)
gvSnippets.Columns.Add(...)
. . .
' This will trigger data binding events
gvSnippets.DataBind();
End Sub
Private Property HeaderTextLanguage As String
Private Property HeaderTextLanguageIso As String
Dim NeedHeaderText As Boolean = False
Private Sub gvSnippets_DataBinding(sender As Object, e As EventArgs) Handles gvSnippets.DataBinding
NeedHeaderText = True
End Sub
Private Sub gvSnippets_DataBound(sender As Object, e As EventArgs) Handles gvSnippets.DataBound
Dim this As GridView = sender
this.Columns(0).HeaderText = String.Format("{0}<br>({1})", HeaderTextLanguage, HeaderTextLanguageIso)
End Sub
Private Sub gvSnippets_RowDataBound(sender As Object, e As GridViewRowEventArgs) Handles gvSnippets.RowDataBound
Dim this As GridView = sender
Dim drv As DataRowView = e.Row.DataItem
If e.Row.RowType = DataControlRowType.DataRow Then
If NeedHeaderText Then
HeaderTextLanguage = drv("language")
HeaderTextLanguageIso = drv("iso")
NeedHeaderText = False
End If
e.Row.Cells(0).Text = Server.HtmlEncode(drv("Somefieldnameofyours"))
End If
End Sub
End Class
Addendum Dealing with Dynamic cells
For a GridView defined as:
<asp:GridView ID="gvSnippets" runat="server"
AutoGenerateColumns="False">
</asp:GridView>
I don't know how you're populating your ds but I'm using a SqlDataSource to fill a table in the Code Behind. Note there is no GridView DataSourceID above:
<asp:SqlDataSource ID="SqlDataSource1" runat="server"
SelectCommand="select top 10 user_id, user_name, user_logon, 'English' as language, 'en' as iso from tbl_users"
ConnectionString='<%$ ConnectionStrings:MyConnectionString %>'>
</asp:SqlDataSource>
Then in the Code Behind I can do this:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
GetDataSetAndPopulate(gvSnippets)
End Sub
Private Sub GetDataSetAndPopulate(gv As GridView)
Dim view As DataView = SqlDataSource1.Select(DataSourceSelectArguments.Empty)
Dim table As DataTable = view.ToTable()
Dim ds As DataSet = New DataSet()
ds.Tables.Add(table)
For Each dc As DataColumn In ds.Tables(0).Columns
Dim field As New BoundField
field.DataField = dc.ColumnName
field.HeaderText = dc.ColumnName
gv.Columns.Add(field)
Next
gv.DataSource = ds
gv.DataBind()
End Sub
And now the Gridview is populated dynamically and you can still handle all the formatting during the DataBinding events as needed.
Here's a solution I came up with that works in my particular case.
I am building the data to populate the GridView in code. I create a DataTable, add columns to it, and then populate those columns. Like:
dim dslang=GetListOfLanguages()
dim dtgv=new DataTable()
for each row as DataRow in dslang.tables(0).rows
dim language_name=row("name")
dim language_code=row("code")
dtgv.columns.add(String.format("{0}<br/>({1})",language_name, language_code)
end for
... bunch of other stuff ...
... inside a loop that reads the data ...
dim outrow=dtgv.NewRow()
... get data for a specific language ...
outrow(language_code)=text
... later ...
my_gridview.datasource=dtgv
my_gridview.databind()
So my solution:
When creating the GridView, set HtmlEncode=false. This makes the header display correctly.
When populating the data, say
outrow(language_code)=HttpUtility.HtmlEncode(text)
So I add the data to the datatable that will ultimately be used as the datasource for the gridview already encoded, so I don't need to rely on the Gridview encoding it.
I consider this a mediocre solution, as it only works because I am populating GridView from a DataTable that I build with code. If I was populating the GridView directly from a DataSource specified in markup, or from a DataSet created by a database query, there'd be no convenient place to put the HttpUtility.HtmlEncode call.

VB.NET Obj Ref not set in datetime

I've seen similar questions through extensive 'google-ing' but none have been able to sort this issue out, the error I'm getting from VS13 is below:
An exception of type 'System.NullReferenceException' occurred in
my.dll but was not handled in user code. Additional information:
Object reference not set to an instance of an object.
Simply put I want a default date value to populate within the calendar textbox so the user doesn't have to choose a date, or if they forget etc it'll put the system time in.
I've tried converting toString etc and I get the same error.
Any help would be gratefully received.
Thanks in advance.
Code behind:
Public Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
Dim SrtDateTxt As New TextBox
SrtDateTxt = ListView1.FindControl("StartDateTextBox")
SrtDateTxt.Text = DateTime.Now
End If
End Sub
And the aspx that the above code behind relates to:
<asp:TextBox ID="StartDateTextBox" runat="server" Text='<%# Bind("StartDate") %>' Width="150px"/>
<act:CalendarExtender ID="CalendarExtender1" runat="server" TargetControlID="StartDateTextBox" Format="yyyy-MM-dd"></act:CalendarExtender>
First i want to suggest to change Option Strict to "On" in your project's settings. That won't you prevent from compiler errors but from nasty runtime errors. Fixing the compiler errors will teach you much about the types in the .NET framework.
Then for example this will not compile anymore:
SrtDateTxt.Text = DateTime.Now
You need to assign a string instead of a Date:
SrtDateTxt.Text = DateTime.Now.ToString() ' or ToShortDateString()
Next, this will not prevent you from a NullRefernceException:
Dim SrtDateTxt As New TextBox
If you assign another value to this variable one line afterwards:
SrtDateTxt = ListView1.FindControl("StartDateTextBox")
So i assume that SrtDateTxt is Nothing because there is no control with that ID in the ListView but in one of it's ListViewItems(which are different NamingContainers).
Therefore you get the exception at the next line when you try to access a property
SrtDateTxt.Text = DateTime.Now ' at .Text
A ListView is meant to be used for multiple items. So you need to use the correct ListViewItem.
For Each item As ListViewItem In ListView1.Items
Dim StartDateTextBox = DirectCast(item.FindControl("StartDateTextBox"), TextBox)
' ... '
Next
This loops all items, i don't know if that is what you want to do.

Listview - Capture text from dynamically created textbox on Update

I have a database and a bound Listview with dynamically created controls. I have been attempting to find a way to capture the new value using markup as
<asp:ListView ID="ListView1" runat="server" DataSourceID="SqlDataSource1" DataKeyNames="ID" OnItemUpdating="ListView1_ItemUpdating">
and code behind as
Protected Sub ListView1_ItemUpdating(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.ListViewUpdateEventArgs) Handles ListView1.ItemUpdating
Dim capString As String = String.Empty
capString = e.NewValues
End Sub
This fails with the error Unable to cast object of type 'System.Collections.Specialized.OrderedDictionary' to type 'System.String'
I'm hoping someone could help me identify either a better way to accomplish capturing this data, or if it is possible to cast this data and how to do it in code.
Try
Dim capString As String = String.Empty
capString = e.NewValues(1) As String
Substitute 1 with an appropriate index for your capString.

visual basic asp.net dropDownList not populating with values

I have an asp.net Visual Basic web site, and I am using a stored procedure to get values to populate a drop-down list.
However, I have two issues. If I put the method to fill the drop-down list within my If Not IsPostBack statement in the page load event, then the whole list is filled with items saying 'System.Data.DataViewRow' instead of the actual values. If I put it outside this 'if' statement but still in my page load event, I get the correct values, but no matter what I select, when I leave the drop-down it reverts back to the top item instead of the selected item.
What am I doing wrong??
Edit: I have now added the DataTextField as suggested by Nic and put the method inside my 'If Not IsPostBack' event as suggested by Lee Bailey. However, my drop-down is still showing all values as 'System.Data.DataViewRow' so I don't know if Lee's solution has worked or not! Any other ideas on the issue of showing the values! I have updated my code below to reflect the changes.
The visual basic:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
bodyPanel.Visible = False
drpRegion_fill()
End If
End Sub
Protected Sub drpRegion_fill()
Dim sqlConn As SqlConnection
sqlConn = New SqlConnection
sqlConn.ConnectionString = ConfigurationManager.ConnectionStrings("ConnString").ConnectionString
Dim drpRegionCmd As SqlCommand
drpRegionCmd = New SqlCommand("getRegionName", sqlConn)
drpRegionCmd.CommandType = CommandType.StoredProcedure
Dim drpRegionAdp As SqlDataAdapter
drpRegionAdp = New SqlDataAdapter(drpRegionCmd)
Dim drpRegionDs As DataSet
drpRegionDs = New DataSet
sqlConn.Open()
drpRegionAdp.Fill(drpRegionDs)
With drpRegion
.DataSource = drpRegionDs
.DataBind()
.DataValueField = "regionName"
.DataTextField = "regionName"
.SelectedIndex = 0
End With
sqlConn.Close()
End Sub
The markup:
<asp:Panel ID="panelRegion" runat="server" Height="160px" Width="71%" CssClass="inlineBlock">
<h2>Region:</h2>
<asp:dropDownList runat="server" AutoPostBack="true" ID="drpRegion" />
</asp:Panel>
The SQL procedure returns a two-column dataset with 'regionID' as column 1, and 'regionName' as column2.
I've spent about two days on this now, trying various things and reading all the books I can! I have never had this issue in C# when I have performed the same operation and I cannot for the life of me think what I've missed in the VB...
It does not look as though you are setting the DataTextField property of your DropDownList:
With drpRegion
.DataSource = drpRegionDs
.DataValueField = "regionName"
.DataTextField = "fieldToDisplayAsText"
.SelectedIndex = 0
.DataBind()
End With
source:
MSDN DataTextField
It's reverting back to the original value because you are re-binding the values to the dropdown after a postback. Changing the selected item is triggering a postback because you have the AutoPostBack property set to true. I would call drpRegion_fill() only if it's not a postback. Setting the DataTextField as Ric mentioned should solve the problem regarding 'System.Data.DataViewRow'

ASP.NET get hidden value from list view on ItemCommand

I have LinkButton and HiddenField in a list view. I want to get the hidden value from HiddenField, so I can store it in Session and when a LinkButton is clicked it transfer the hidden value ( stored in Session) to another page. But I get this error message "Object reference not set to an instance of an object." Here's the function:
Protected Sub lvTimeSheet_ItemCommand(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.ListViewCommandEventArgs) Handles lvTimeSheet.ItemCommand
Dim id As HiddenField = TryCast(e.Item.FindControl("hfTimeSheetId"), HiddenField)
Dim myId As String = id.Value.ToString
Session("myId") = myId
Server.Transfer("Destination.aspx")
End Sub
The mark-up
</asp:LinkButton><asp:HiddenField ID="hfTimeSheetId1" runat="server" Value='<%# Eval("hfTimeSheetId") %>' />
Every time the LinkButton is clicked, it causes error with above error message. Thank you for any input.
My guess would be that the FindControl isn't finding the hfTimeSheetId control within the row. Do you have it designated as a managed control (i.e. runat="server")?
Also, it might help if you provided the ASPX code to see how you're defining the controls.
The FindControl is returning null, hense the exception. Try changing it to:
Dim id As HiddenField = TryCast(e.Item.FindControl("hfTimeSheetId1"), HiddenField)

Resources