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.
Related
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.
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.
I searched the web and found the example, but I still get it right. I have a multiple datakey on datagrid and I get index out of range error. Would someone help me out. Thanks in advance.
There is my aspx
<asp:datagrid id="dgrTrans" runat="server" autogeneratecolumns="False" gridlines="Both" borderstyle="NotSet" cssclass="dgrd w97p" cellpadding="2"
horizontalalign="center" datakeyNames="ID, Description" >
There is my code to retrieve the value on ItemDataBound
Select Case e.Item.ItemType
Case ListItemType.Item, ListItemType.AlternatingItem, ListItemType.EditItem
Dim currentItem As DataGridItem = CType(e.Item, DataGridItem)
Dim dKey As DataKey = Me.dgrTranscripts.DataKeys(currentItem.ItemIndex)
Dim cn As String = dKey("Description").ToString()
end select
I also tried the following code, but I get the "Conversion from string "" to type 'Integer' is not valid." error
Dim cn As String = dgrTranscripts.DataKeys(e.Item.DataItem("Description)).ToString
The index in your case can only be 0 or 1 because there are only two of the keys. You are trying to retreive DataKey with index that equals to currentitem.ItemIndex, which can be as big as many items you have, therefore you are getting an out of range error. You need to use either 0 or 1 as a DataKey index. I cannot give you a definitive answer because you did not specify what exactly you are trying to do...
EDIT:
Instead of ItemDataBound, use DataBound event and loop through every row to get its value.
Here is an example with GridView
Protected Sub GridView1_RowDataBound(sender As Object, e As EventArgs) Handles GridView1.DataBound
For Each row As GridViewRow In GridView1.Rows
Dim cn = GridView1.DataKeys(row.RowIndex).Value
Next
End Sub
On ItemDataBound, DataGrid does not know that there are keys yet. They will be assigned on DataBound
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)
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()