Formatting text in an ASP.Net Boundfield - asp.net

I have a webform with a a couple of boundfields in an edit window as follows:
<asp:BoundField DataField="TS_TITLE" HeaderText="Title" SortExpression="TS_TITLE" HeaderStyle-VerticalAlign="Top" HtmlEncode="True" >
<ControlStyle Width="500px" />
</asp:BoundField>
<custom:BoundTextBoxField DataField="TS_DESCRIPTION" HeaderText="Desription" HeaderStyle-VerticalAlign="Top" SortExpression="TS_DESCRIPTION"
TextMode="MultiLine" Rows="20" Columns="100" Wrap="True" HtmlEncode="True" />
I'm using the Html Encode property of the BoundField to secure against cross-site scripting attacks. What I would like to do is when a user reopens the edit window, I want the encoded html to be decoded and presented, html tags and all. My problem is that when I try to decode the html in the code-behind, under the Page_Load function, it doesn't get set when the page is presented to the user, i.e. it has no effect. Here is the snippet of code from the Page_Load:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim dvrTest As DetailsViewRowCollection = DetailsView1.Rows
Dim DescriptionTB As TextBox = dvrTest.Item(1).Cells(1).Controls(0)
DescriptionTB.Text = HttpUtility.HtmlDecode(DescriptionTB.Text)
End Sub 'Page_Load
When debugging I can see the html decoded text as it should look, my guess is that there's an additional databind that occurs after the Page_Load exits that resets the BoundTextBoxField. Just a note, I've tested this on both the BoundField and BoundTextBoxField and the effect is the same on both.
I had a similar issue with a dropdown list I'm using in another part of my application, only there I was using the onLoad event to call a function to do data manipulation after the page was loaded and databound. Unfortunately, Boundfield doesn't seem to have that event, the closest thing I've found is DataFormatString property, but that only seems to be useful when working with dates and currency.
UPDATE:
In case anyone was wondering, even with the HTMLEncode property set to false, I get the encoded text when the Edit Window is Reloaded.
UPDATE 2:
Tried overriding the OnDataBinding method, but that didn't seem to do anything.
Protected Overrides Sub OnDataBinding(ByVal e As System.EventArgs)
Me.OnDataBinding(e)
Dim dvrTest As DetailsViewRowCollection = DetailsView1.Rows
Dim DescriptionTB As TextBox = dvrTest.Item(1).Cells(1).Controls(0)
DescriptionTB.Text = HttpUtility.HtmlDecode(DescriptionTB.Text)
End Sub

Got it. Since my boundfields were encased in a DetailsView, I used the onLoad event of the DetailsView to call a function in the code-behind to decode the any html within the text of the Boundfields
''' <summary>
''' Decodes any HTML formatted tags in the Title and Description Textboxes of the Edit Window
''' </summary>
''' <param name="sender"></param>
''' <param name="e"></param>
''' <remarks></remarks>
Protected Sub HTMLDecode(ByVal sender As Object, ByVal e As System.EventArgs)
If Page.IsPostBack = False Then
''Grab the Title and Description text boxes from the RowCollection
Dim dvrTest As DetailsViewRowCollection = DetailsView1.Rows
Dim TitleTB As TextBox = dvrTest.Item(0).Cells(1).Controls(0)
Dim DescriptionTB As TextBox = dvrTest.Item(1).Cells(1).Controls(0)
''Decode HTML tags that are in either text box
DescriptionTB.Text = HttpUtility.HtmlDecode(DescriptionTB.Text)
TitleTB.Text = HttpUtility.HtmlDecode(TitleTB.Text)
End If
End Sub 'HTMLDecode
And calling it in the DetailsView using the onLoad event
<asp:DetailsView ID="DetailsView1" runat="server" Height="260px" Width="500px" AutoGenerateRows="False"
DataKeyNames="TS_ID" DataSourceID="SqlDataSource2" EnableModelValidation="true"
GridLines="Both" Font-Names="Arial" HorizontalAlign="Center" OnLoad="HTMLDecode" >
If there are any more straightforward alternatives, I'd be glad to hear them.

Related

Determining which control fires an event in a listview

I asked this on the telerik forums, but sometimes responses can be slow there. I was wondering if anyone here know how to go about this.
I am in a situation where a user will have a variable number of items and beside each item I want a RadNumericTextBox. I was thinking of using the RadListView and setting the template to be the item name and a RadNumericTextBox associated with it. I want to ignore the edit, create, and the more advanced features of the RadListView. I just want a list of items with the input boxes that will auto post back when a user has changed the value.
The problem I am facing is when a user changes a number in the text box, how do I know which text box this is? I was looking to see if there was a attribute on RadNumericTextBox that could hold an arbitrary value such as my item key so I would know which number they changed. However, I don't see such an attribute.
Is there some way I can make a determination which text box they edited when I auto post back?
In case anyone asks, I do not want to force my user to click a button to make the row go into edit mode, change the number, then click a button to save the row.
You could do this with a Repeater control.
Include a RadNumericTextBox in the repeater's item template, and then write a server-side event handler for it. The client ID of the text box can be accessed through the event handler's sender object, but if that isn't enough information you can rely on the repeater's data source to relate whatever data you need with each text box.
The simplest way might be to use the Label attribute of the text box. Here's an example:
ASPX:
<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
<asp:Repeater ID="Repeater1" runat="server">
<ItemTemplate>
<br />
<telerik:RadNumericTextBox ID="radNTB" runat="server" AutoPostBack="true" OnTextChanged="radNTB_TextChanged" ClientIDMode="Predictable"></telerik:RadNumericTextBox>
</ItemTemplate>
</asp:Repeater>
VB:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
Dim dt As New DataTable
dt.Columns.Add("Column1", GetType(String))
For i As Integer = 1 To 5
Dim row = dt.NewRow
row.Item("Column1") = "TextBox" & i.ToString
dt.Rows.Add(row)
dt.AcceptChanges()
Next
Repeater1.DataSource = dt
Repeater1.DataBind()
End If
End Sub
Private Sub Repeater1_ItemDataBound(sender As Object, e As System.Web.UI.WebControls.RepeaterItemEventArgs) Handles Repeater1.ItemDataBound
If (e.Item.ItemType = ListItemType.Item Or e.Item.ItemType = ListItemType.AlternatingItem) Then
Dim tb As RadNumericTextBox = e.Item.FindControl("radNTB")
tb.Label = DataBinder.Eval(e.Item.DataItem, "Column1").ToString()
End If
End Sub
Public Sub radNTB_TextChanged(sender As Object, e As EventArgs)
Dim ntb As RadNumericTextBox = sender
Response.Write(ntb.Label)
End Sub
What you can do is by the item your binding the listview with the data source,
make the id of the RadNumericTextBox equals to your item key that you want to pass.
In the RadNumericTextBox TextChanged event cast the sender object to RadNumericTextBox type. in this
case you will get the unique item key you are looking for.
example :
<asp:FormView ID="frmViewPicture" runat="server">
<EditItemTemplate>
<telerik:RadNumericTextBox ID='Eval("ItemKey")'
OnTextChanged="radTxtNewPrice_TextChanged" AutoPostBack="true">
</telerik:RadNumericTextBox>
</EditItemTemplate>
</asp:FormView>
Make sure the item key is unique and available in your data source, other wise you will get an exception.
protected void radTxtNewPrice_TextChanged(object sender, EventArgs e)
{
Telerik.Web.UI.RadNumericTextBox txtRadNumericTextBox= (Telerik.Web.UI.RadNumericTextBox)sender;
var itemKey = txtRadNumericTextBox.ID;
// Do Your Logic Here
}
Hope this is helpful.

ImageButton not firing

I have the following button:
<asp:ImageButton ID="imgbtnEditInfo" runat="server" ImageUrl="~/images/EditInformation.png" AlternateText="EditInformation" CommandName="EditDetails" CommandArgument="<%# Container.DataItemIndex %>" OnClick="lnkEdit_Click" Enabled="true" />
I have the following method but looks like it is not hitting the method:
Protected Sub lnkEdit_Click(ByVal sender As Object, ByVal e As System.EventArgs)
End Sub
Wondering if I am missing something. I put a breakpoint on the Protected Sub lnkEdit_Click but on click of the imagebutton I do not go there.
You're working with Data Controls (GridView or DataList etc). To respond to the button/linkbutton/imagebutton events, you must have to handle the parent - data control's events.
Without seeing more of your page it is hard to say. A couple things to check:
Is the ImageButton inside a <form runat="server">?
Have you compared your page to the VB sample at ImageButton Class to see if anything might have been missed?

GridView Row Redirect to Pre-filled DetailsView on Button Click

Background:
I have a GridView which gets populated from an SqlDataSource via DataSourceID. The rows show some summary data from an SQL View. Upon clicking a row, I would like to take my user to another page with a DetailsView control which gets populated with the full set of values from the DB related to the row clicked. My user should be able to edit the data, download files associated with the record, and create a new record of a different type based on said data.
Error:
All examples that I've found for Clickable GridView rows end up with some variation of the error Invalid postback or callback argument. Event validation is enabled using <pages enableEventValidation="true"/> in configuration or <%# Page EnableEventValidation="true" %> in a page.
Naturally, I do not want to expose my site to vulnerabilities by disabling event validation. I need to be able to grab the Primary key of the clicked row's associated record and perform operations on that data on a subsequent page, probably via a DetailsView. I suspect my errors are a result of my setup, which is why I included those details.
My Questions Are:
How do I capture the Primary Key of clicked row?
How do I, onclick, forward to a "details" page with a pre-filled form containing data from the row record that was clicked?
HERE'S THE COMPLETE SOLUTION
**thanks again to Icarus' help
'Fetch the DataKey ("ID"), seems to work
Protected Sub RowBind(ByVal sender As Object, ByVal e As GridViewRowEventArgs) _
Handles GridView1.RowDataBound
If e.Row.RowType = DataControlRowType.DataRow Then
Dim datakey As String = GridView1.DataKeys(e.Row.RowIndex).Value.ToString()
End If
End Sub
'Handle button click
Protected Sub RowClick(ByVal sender As Object, ByVal e As GridViewCommandEventArgs) _
Handles GridView1.RowCommand
If e.CommandName = "Select" Then
'Add to session variable; translate the index of clicked to Primary Key
Session.Add("DetailsKey", GridView1.DataKeys(e.CommandArgument).Value.ToString)
Response.Redirect("details.aspx")
End If
End Sub
And My Markup
<asp:GridView ID="GridView1" runat="server" DataSourceID="GridView1SDS"
DataKeyNames="ID" AllowPaging="True" AllowSorting="True">
'<!-- Styling -->
<Columns>
<asp:ButtonField ButtonType="Button" Text="Details" CommandName="Select" />
</Columns>
</asp:GridView>
<asp:SqlDataSource ID="GridView1SDS" runat="server"
ConnectionString="<%$ ConnectionStrings:dbConnectionString %>"
SelectCommand="select * from viewRequestQueue">'<!-- An SQL View -->
</asp:SqlDataSource>
Forwarded Page VB & Markup
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
GridView2SDS.SelectCommand = "select * from viewRequestQueue where ID = " _
+ Session.Item("DetailsKey").ToString
End If
End Sub
<asp:DetailsView ID="GridView2" runat="server" DataSourceID="GridView2SDS">
'<!-- Styling -->
</asp:DetailsView>
<asp:SqlDataSource ID="GridView2SDS" runat="server"
ConnectionString="<%$ ConnectionStrings:dbConnectionString %>">
</asp:SqlDataSource>
Also, please note that if the SelectCommand for your DataSource is handled in the codebehind, that means the DataBind will overwrite your <Columns> in the markup. To get around this, you should define the columns in the code behind before the DataBind. So say I wanted to add another ButtonField column to my forwarded page (notice the SelectCommand is not provided in the markup), I added the following before the setting the SelectCommand and doing the DataBind:
Dim id As New ButtonField()
id.ButtonType = ButtonType.Button
id.Text = "Load"
id.CommandName = "Select"
PubDetails.Columns.Add(id)
You need to declare the KeyNames of the items you are binding on your markup. For example:
<asp:GridView id="grid" runat="Server" DataSourceID="YourSQLDataSource" DataKeyNames="ID,Name" />
In your case, you seemed to be handling the OnRowDataBound event. You can do this to grab the key inside RowBound:
If e.Row.RowType = DataControlRowType.DataRow Then
Dim datakey As String = GridView1.DataKeys(e.Row.RowIndex).Value.ToString() 'get the datakey
End If
Your second question is difficult to answer because you did not specify how you want the user to be redirected, if from the client side using Javascript or from the Server side. You also did not specify how do you expect to populate the details on the Details page. Do you expect to read a parameter from the URL and use it to get the record details from the database?

access selectcommand using codebehind

How can I change my selecommand, and keep it through the remainder of the page (when using pagination, sorting)?
I have a page of checkboxes:
<input type="checkbox" name="checkbox_1" />
<input type="checkbox" name="checkbox_2" />
<input type="checkbox" name="checkbox_3" />
<asp:Button runat="server" Id="CustomButton" text="Create Report" PostBackUrl="report.aspx?"/>
Then on report.aspx I want to generate a standard listview based on the selections in the checkbox.
<asp:ListView runat="server" ID="ReportListView" DataSourceID="ReportListViewSDS">
<LayoutTemplate runat="server">
...<asp:PlaceHolder runat="server" ID="itemPlaceHolder" />...
</LayoutTemplate>
<ItemTemplate>
...
</ItemTemplate>
</asp:ListView>
I want to be able to sort and paginate that listview. This is an idea of what i want in the code behind:
Protected Sub ReportListView_PreRender(ByVal sender As Object, ByVal e As System.EventArgs)
' What's the correct way to reference the listview?
' When I use the below code i get "ReportListView is not declared...."
' ReportListView.SqlCommand = "SELECT " & checkbox1 & ", " & checkbox2 & " WHERE..."
End Sub
I'm not sure if I'm even going in the right direction with this, any help is appreciated. Will the changes i make to the sql command in the PreRender function hold when I have applied pagination or sorting to the listview?
If I understand your question correctly, you want to open a new page and use the prior page's values in the select statement for the ListView's SqlDataSource on the new page, correct?
First, a few observations:
In your first page, you appear to be intending to call the second page with a query string (PostBackUrl="report.aspx?), but you don't appear to set the query string.
Your PreRender event for the ListView control has the wrong signature. It only takes one argument, EventArgs:
Protected Sub ReportListView_PreRender(ByVal e As EventArgs)
Your ListView appears to be using a SqlDataSource as it's binding source (DataSource="ReportListViewSDS"). More about that below.
There is no SqlCommand property or method for the ListView control.
Since you're binding the ListView to a SqlDataSource, it'd be simplest to set the Select command and the parameters in the markup, like this:
<asp:SqlDataSource ID="ReportListViewSDS" runat="server"
SelectCommand="SELECT checkbox1, checkbox2, checkbox3 FROM <table> WHERE checkbox1 = #parm1 AND checkbox2 = #parm2 AND checkbox3 = #parm3">
<SelectParameters>
<asp:FormParameter FormField="checkbox_1" Name="parm1" />
<asp:FormParameter FormField="checkbox_2" Name="parm2" />
<asp:FormParameter FormField="checkbox_3" Name="parm3" />
</SelectParameters>
</asp:SqlDataSource>
Replace <table> in the SelectCommand with the name of your table. You can adjust the names of the columns you're selecting, as well as the parameters you're using, as desired. I simply used 3 checkboxes as that's what you had in the code you posted.
Also note, NO VALIDATION of the parameters will be done by the SqlDataSource, so if you want to prevent SQL Injection attacks and other security risks, you'll want to do validation in the Selecting event of the SqlDataSource.
More information can be found here:
SqlDataSource Class
FormParameter Class
Actually this was much easier than I thought. Sorry, just a newbie mistake i guess. i ended up simply doing:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim SqlCommand As String
' create the sql command using the Request.Form vars i wanted.
' ...
' Run the sql command, I can access the listview directly, just like a global variable:
ReportListView.SelectCommand = SqlCommand
ReportListView.DataBind()
End Sub
And that seemed to do it. Actually very easy.

add an initial line-through text-decoration on a label in a asp listview

My goal is to display a list of tasks with checkboxes. Checking the checkbox for a task will update the display of the task so a line-through text decoration will appear. Everythign is working great, except I can't figure out how to initially show the list of tasks with a line-through if they are completed, or normal if the task is not completed. Here's code excerpts:
<asp:Listview .../>
...
<ItemTemplate>
<asp:HiddenField ID="TaskCompleted" runat="server" Value='<%#Bind("TaskCompleted")%>'/
<asp:Checkbox ID="CompletedCheckbox" runat="server" AutoPostBack="True" OnCheckedChanged="CompletedCheckboxChange" Checked='<%#IIf(Eval("TaskCompleted"), "True", "False")%>' />
<asp:Label id="TaskLabel" text='<%#Eval("TaskDesc")%>' runat="server" />
</ItemTemplate>
...
</asp:ListView>
Then the code behind (minus the database stuff which works fine):
Protected Sub CompletedCheckboxChange( ByVal sender As Object, ByVal e As EventArgs )
Dim Completed As CheckBox = TryCast( sender, CheckBox )
Dim AnnualProgramTasksId as HiddenField = TryCast(Completed.Parent.FindControl("AnnualProgramTasksId"), HiddenField)
Dim TaskLabel As Label = TryCast(Completed.Parent.FindControl("TaskLabel"), Label)
If Completed.Checked Then
'update task displayed, give it a line-through
TaskLabel.Style("text-decoration") = "line-through"
Else
'update task displayed, give it a line-through
TaskLabel.Style("text-decoration") = "none"
End If
End Sub
So this works great, when I click on a checkbox the lable gets a line-through or none based on the checkbox. Only problem is when I initially load the page, I can't figure out how to update the style of TaskLabel to show a line-through or not. I've tried some various routes, but nothing is panning out. Any ideas?
This is how I have always done something like whay you are trying to.
Try
<asp:Label id="TaskLabel" text='<%#Eval("TaskDesc")%>' runat="server"
OnDataBinding="TaskLabel_DataBinding" />
and
Protected Sub TaskLabel_DataBinding( ByVal sender As Object, ByVal e As EventArgs )
Dim Completed As CheckBox = TryCast(DirectCast( sender, Control).Parent.FindControl("CompletedCheckbox"), CheckBox)
CompletedCheckboxChange(Completed, EventArgs.Empty)
End Sub

Resources