UpdatePanel seems to re-encode characters in the page title? - asp.net

I have pages with special characters in the title for proper typography, for example it says Exchange ‘07 Groups" with a proper apostrophe, not a single quote. The HTML entity for the apostrophe is ‘
So, I've found that if I set the page title from VB, the title displays just fine, but as soon as an update panel updates that HTML entity gets re-encoded and displays incorrectly as "Exchange ‘07 Groups"
So here's my code where I simply set the page title, then an update panel, and a button to update it...
<script runat="server">
Protected Sub Page_Load(...) Handles Me.Load
Page.Title = "Exchange ‘07 Groups"
End Sub
Protected Sub uxLnkDoClick(ByVal sender As Object, ByVal e As System.EventArgs)
uxLitLoaded.Text = "Loaded!"
End Sub
</script>
<!DOCTYPE html>
<html>
<head runat="server"></head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager runat="server"></asp:ScriptManager>
<asp:UpdatePanel runat="server" UpdateMode="Conditional">
<ContentTemplate>
<asp:LinkButton runat="server" ID="uxLnkDo" OnClick="uxLnkDoClick" Text="Do Something" />
<asp:Literal runat="server" ID="uxLitLoaded" />
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="uxLnkDo" />
</Triggers>
</asp:UpdatePanel>
</form>
</body>
</html>
What can be done about this?

In your code to set the page title, wrap the text in Server.HtmlDecode:
Page.Title = Server.HtmlDecode("Exchange ‘07 Groups")

I had the same situation with the SM (service mark, as opposed to TM for trademark) which we did setting the page title with Page.Title = "My Company &#8480"; . It reencoded it upon postback.
What we did is in the page head we statically added it
< title >My Company ℠< /title >
Worked like a charm.

The reason it displays it incorrectly is because .Net is attempting to be safe and HTML encode the title (for prevention of the multiple types of attacks that are possible).
In ASP.Net MVC, you can now use the Html.Raw() method. As far as straight ASP.net, I don't know what the method would be.

add this check
if(!Page.IsPostBack)
{
Page.Title = "Exchange ‘07 Groups"
}

or you can simply set the title property in html if its not dynamic!

Related

Understanding UpdatePanels

I am trying to understand UpdatePanels and best practise for using them.
I am using .Net4.0 with VB.Net.
The idea is to create a conversation app for a clients website and so I have control called Convo.ascx. Code added below.
<asp:UpdatePanel runat="server">
<ContentTemplate>
<h2>Conversation</h2>
<p><asp:Literal ID="lit1" runat="server" /></p>
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<asp:Button ID="Button1" runat="server" Text="Button" />
</ContentTemplate>
</asp:UpdatePanel>
Convo.ascx.vb
Partial Class Convo
Inherits System.Web.UI.UserControl
Protected Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
lit1.Text = lit1.Text & "<p>" & TextBox1.Text & "</p>"
End Sub
End Class
On a load page (Default.aspx) I have:
<%# Page Language="VB" AutoEventWireup="false" CodeFile="Default.aspx.vb" Inherits="_Default" %>
<%# Reference Control="~/Convo.ascx" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<asp:scriptmanager ID="Scriptmanager1" runat="server"></asp:scriptmanager>
<div>
<asp:UpdatePanel runat="server">
<ContentTemplate>
<asp:Button ID="Button1" runat="server" Text="Add Conversation" />
<asp:PlaceHolder ID="phConversation" runat="server">
</asp:PlaceHolder>
</ContentTemplate>
</asp:UpdatePanel>
</div>
</form>
</body>
</html>
With Codebehind Default.aspx.vb as
Partial Class _Default
Inherits System.Web.UI.Page
Protected Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
AddConvo()
End Sub
Private Sub AddConvo()
Dim getPh As New PlaceHolder
getPh = CType(Me.FindControl("phConversation"), PlaceHolder)
Dim ucConvo As New Convo
ucConvo = CType(LoadControl("~/Convo.ascx"), Convo)
getPh.Controls.Add(ucConvo)
End Sub
Protected Sub Page_Load(sender As Object, e As EventArgs) Handles Me.Load
AddConvo()
End Sub
End Class
So the Convo I add OnLoad remains on the page after extra as been added been any convo added after load is gone once the button on Convo is hit.
So my question is, how can I have these add and remain? Eventually they will be added to database but right now I am trying to understand UpdatePanels as they will become the foundation for this app.
Is there a very good explanation of multi-use UpdatePanels anywhere?
Thanks in advance
PS, im a hobbiest so only VB responses please
The issue actually isn't with the UpdatePanel, but with ASP.NET. ASP.NET web forms uses a control hierarchy for the entire page, and you are adding the controls to the hierarchy "dynamically". Since you are doing it that way, ASP.NET requires you add the control back into the control hierarchy on every postback to the server. The UpdatePanel is a way to post back to the server, and therefore you must re-add the old user controls and new ones to that hierarchy.
Essentially the UpdatePanel was added to make AJAX easy, but you still have to work within the rules of ASP.NET.

Placeholder Code still visible when "view source code", even though placeholder visible property set to false from code behind

<asp:PlaceHolder ID="pnlThanks" runat="server" Visible="false">
<p><asp:Literal ID="lblReceipt" runat="server"></asp:Literal></p>
</asp:PlaceHolder>
<asp:PlaceHolder ID="pnlForm" runat="server" Visible="true">
<form id="form1" runat="server" class="busgroup-form">
//// All form controls
</form>
</asp:PlaceHolder>
Code Behind file:
Protected Sub submit_Click(ByVal sender As Object, ByVal e As EventArgs) Handles cmdsubmit.Click
form1.Controls.Clear()
pnlForm.Visible = False
pnlThanks.Visible = True
End Sub
So, after submitting form when "pnlThanks" placeholder is visible, I can see proper contents displayed on page. But when I do "view source" on the browser, I see the source code for form and not the content inside "pnlThanks" placeholder.
What am I doing wrong ?
You need to have all of your controls within the <form> tag, because ASP.NET depends upon the form to do postbacks, etc.
You can only have one <form> tag in your page.
Change your code to this:
<form id="form1" runat="server" class="busgroup-form">
<asp:PlaceHolder ID="pnlThanks" runat="server" Visible="false">
<p><asp:Literal ID="lblReceipt" runat="server"></asp:Literal></p>
</asp:PlaceHolder>
<asp:PlaceHolder ID="pnlForm" runat="server" Visible="true">
</asp:PlaceHolder>
</form>
Your code works as expected when I tested it. My guess is there is another pnlForm.Visible = True in your code elsewhere that is executed on your postback.
pnlThanks isn't rendered if visible=false, therefore it won't show in the source. You can use CSS (display=none) to hide it on start and change when needed.

ASP.NET WebForms: Asynchronous UpdatePanel?

First off, I know that what I am doing here seems entirely impractical and not good design, but I am trying to increase performance in this ASPX that contains 8,000+ lines of markup. Because of the complexity of this page (not to mention messiness) and short deadline, rewriting it to use clientside binding with AJAX/JSON is just not an option, so I have to continue to use serverside binding.
The page I am working on contains around 13 individual sections, each one loading its own entity from the database. Right now, the page initially loads ALL entities synchronously, so you can imagine that this page can sometimes take 5 seconds or longer to load. My goal here is to employ a quick fix that will load these sections only when the section is expanded so that we load only the sections that are requested by the user, thus increasing performance and conserving database resources.
The sample code below should be easy to paste right into a VB.NET WebForm if you're interested in trying this out for yourself. Just name the page asyncupdatepanels.aspx.
The problem:
Overall, my solution is working fairly well. In cmUpdate_Click, I use Threading.Thread.Sleep(2000) to simulate a call to the database to retrieve data. When you click one of the buttons, it pauses for 2 seconds and then sets the appropriate Panel's .Visible property to True.
The issue occurs when you click one button and then click the the other before the first one is finished updating. For example, if you click Show Panel 1 then quickly click Show Panel 2, only Panel 2 shows even though both button clicks are triggered in the codebehind.
Maybe asynchronous UpdatePanel is the wrong term to use here. Regardless, I need to find a way to show the panels as if they were executed in separate asyncronous threads. I want to be able to click these buttons pretty much near the same time and have both panels show.
If anyone has any other solutions to my problem that will not require major changes to the way I bind controls in each section, I'd love to hear it. The method I am using now is pretty much a hack, but it will work for now until we eventually rewrite this whole thing in MVC/c#.
Edit: The production code doesn't actually call a Javascript function by use of a button's OnClientClick. Instead, it uses a jQuery accordion. I just wanted to keep the sample code simple. For now, focus on __doPostBack("<%=cmUpdate.ClientID %>", ButtonId); regardless of how it's ultimately called.
ASPX
<%# Page Language="vb" AutoEventWireup="false" EnableEventValidation="false" CodeBehind="asyncupdatepanels.aspx.vb" Inherits="JsonJqueryDevex.asyncupdatepanels" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<script language="javascript" type="text/javascript">
function UpdateIt(ButtonId) {
__doPostBack("<%=cmUpdate.ClientID %>", ButtonId);
return false;
}
</script>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
<div>
<asp:Button ID="cmShow1" Text="Show Panel 1" ClientIDMode="Static" OnClientClick="javascript:return UpdateIt(this.id);" runat="server" />
<asp:UpdatePanel ID="UpdatePanel1" UpdateMode="Conditional" runat="server">
<ContentTemplate>
<asp:Panel ID="pnl1" Visible="false" runat="server">
Panel 1 content
</asp:Panel>
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="cmUpdate" EventName="Click" />
</Triggers>
</asp:UpdatePanel>
<asp:Button ID="cmShow2" Text="Show Panel 2" ClientIDMode="Static" OnClientClick="javascript:return UpdateIt(this.id);" runat="server" />
<asp:UpdatePanel ID="UpdatePanel2" UpdateMode="Conditional" runat="server">
<ContentTemplate>
<asp:Panel ID="pnl2" Visible="false" runat="server">
Panel 2 content
</asp:Panel>
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="cmUpdate" EventName="Click" />
</Triggers>
</asp:UpdatePanel>
<div style="display: none">
<asp:UpdatePanel UpdateMode="Conditional" runat="server">
<ContentTemplate>
<asp:Button ID="cmUpdate" runat="server" />
</ContentTemplate>
</asp:UpdatePanel>
</div>
</div>
</form>
</body>
</html>
Codebehind:
Public Class asyncupdatepanels
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
End Sub
Private Sub cmUpdate_Click(sender As Object, e As System.EventArgs) Handles cmUpdate.Click
Dim Param As String = Request("__EVENTARGUMENT")
Threading.Thread.Sleep(2000)
Select Case Param
Case "cmShow1"
pnl1.Visible = True
Case "cmShow2"
pnl2.Visible = True
End Select
End Sub
End Class
How about disabling the appropriate buttons on click?
Say,
function UpdateIt(ButtonId) {
$('#<%=cmShow1.ClientID %>').attr('disabled', true);
$('#<%=cmShow2.ClientID %>').attr('disabled', true);
__doPostBack("<%=cmUpdate.ClientID %>", ButtonId);
return false;
}
Then, in your code behind, after the sleep, enable them again (cmShow1.Enabled = true / cmShow2.Enabled = true) - the UpdatePanel call will handle the rest.
I would do an AJAX call to your server-side in the page_load event of the page where your updated panel is. You would then call the Update method of your update panel when your processing is done.
You won't have to wait for the processing to be done to do whatever you want to do meanwhile.
Javascript(with jQuery):
function ajaxCall() {
$.ajax({
url: "YourPage.aspx"
});
}
You can process your AJAX call in the Page_Load in your .NET.
I know that you said using AJAX wouldn't be a good option, but this is fairly short and simple.

UserControl causes full postback in UpdatePanel

I'm fighting this problem for few hours now and I'm not getting any closer to solution.
The thing is: I'm having few UpdatePanels on my master page. And then, I have RadTreeViewcontrol on the page, that should cause partial postback each time node is clicked. Everything works fine there.
Since I'm using the same tree on some other pages, I moved this functionality to UserControl. Stuff I've done before, so no problem. Moved some code to ascx, created some events. Everything always worked for me well. But not now.
RadTreeView is nested inside UserControl, and this control on master page with update panels, see below:
<asp:Panel ID="pnlContentWrapper" runat="server" CssClass="ContentWrapper">
<div id="HeaderBreadCrumb">
<asp:ContentPlaceHolder ID="HeaderBreadCrumbContent" runat="server" />
</div>
<div id="HeaderMenu">
<asp:UpdatePanel ID="upnlTreeMenu" runat="server">
<ContentTemplate>
<asp:ContentPlaceHolder ID="HeaderMenuContent" runat="server" />
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="treeProductTree" />
</Triggers>
</asp:UpdatePanel>
</div>
<div id="TreeDiv">
<fp:ProductTree ID="treeProductTree" runat="server" />
</div>
<asp:Panel ID="ContentDiv" ClientIDMode="Static" runat="server">
<asp:UpdatePanel ID="upnlTreeContent" runat="server">
<ContentTemplate>
<asp:ContentPlaceHolder ID="TreePageContent" runat="server" />
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="treeProductTree" />
</Triggers>
</asp:UpdatePanel>
</asp:Panel>
</asp:Panel>
And the user control is really simple:
<%# Control Language="vb" AutoEventWireup="false" CodeBehind="ProductTree.ascx.vb"
Inherits="ProductTree" %>
<div>
<telerik:RadTreeView ID="treeProductTree" ClientIDMode="Static" runat="server" EnableDragAndDrop="false"
SkinID="CustomSkin" CssClass="MasterProductTree" DataFieldID="NodeId" DataFieldParentID="NodeParentId"
DataTextField="NodeName" DataValueField="NodeId" />
</div>
And some code behind:
Imports Telerik.Web.UI
Public Class ProductTree
Inherits System.Web.UI.UserControl
Public Event NodeExpand As EventHandler(Of ProductTreeNodeExpandEventArgs)
Public Event SelectedNodeChange As EventHandler
Protected Sub ProductTree_NodeExpand(ByVal sender As Object, ByVal e As RadTreeNodeEventArgs) _
Handles treeProductTree.NodeExpand
Dim nodeId As Integer = CInt(e.Node.Value)
Dim evetArgs = New ProductTreeNodeExpandEventArgs(nodeId)
RaiseEvent NodeExpand(Me, evetArgs)
//'some logic
End Sub
Protected Sub ProductTree_OnNodeClick(ByVal sender As Object, ByVal e As RadTreeNodeEventArgs) _
Handles treeProductTree.NodeClick
RaiseEvent SelectedNodeChange(Me, New System.EventArgs())
End Sub
End Class
What I don't know is: why is this causing full postback instead of partial? I suspect that it may have something to do with raising my for SelectedNodeChange, but I don't know how to deal with it other way. I need to let other components know, that node selection changed. How can I improve this to make it work with UpdatePanels?
Suspect that registering a UserControl as an AsyncPostbackTrigger is not going to get you very far. The UC itself is not a postback control, rather, it contains one. I would expose the tree control as a public property of the usercontrol, and then in code behind in your containing page, register the tree control itself as the trigger, rather than the UserControl.
Check this for a similar situation... it's not a great Q&A thread but it shows the basic gist.
Well, I have the similar situation but it's a little more complicated.
User control causing postback is actually added dynamically depending on the request parameter value.
I was so glad the ClietIDMode paramter was added, I didn't think a problem like tat would be overlooked by Microsoft.
The same problem that I am facing right now... I thing that could be fixed by wrapping up the UC with an iFrame.

Hidden/Shown AsyncFileUpload Control Doesn't Fire Server-Side UploadedComplete Event

I recently came across the AsyncFileUpload control in the latest (3.0.40412) release of the ASP.Net Ajax Control Toolkit. There appears to be an issue when using it in a hidden control that is later revealed, such as a <div> tag with visible=false.
Example:
Page code -
<%# Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="act" %>
.
.
.
<act:ToolkitScriptManager runat="server" ID="ScriptManager1" />
<asp:UpdatePanel runat="server" ID="upnlFileUpload">
<ContentTemplate>
<asp:Button runat="server" ID="btnShowUpload" Text="Show Upload" />
<div runat="server" id="divUpload" visible="false">
<act:AsyncFileUpload runat="server" id="ctlFileUpload" />
</div>
</ContentTemplate>
</asp:UpdatePanel>
Server-side Code -
Protected Sub ctlFileUpload_UploadedComplete(ByVal sender As Object, ByVal e As AjaxControlToolkit.AsyncFileUploadEventArgs) Handles ctlFileUpload.UploadedComplete
End Sub
Protected Sub btnShowUpload_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnShowUpload.Click
divUpload.Visible = True
End Sub
I have a breakpoint on the UploadedComplete event but it never fires. However, if you take the AsyncFileUpload control out of the <div>, making it visible at initial page render, the control works as expected.
So, is this a bug within the AsynchUploadControl, or am I not grasping a fundamental concept (which happens regularly)?
First, make sure your tag has the following attribuytes - enctype="multipart/form-data" method="post" Secondly, you have to have the AsyncFileUpload in an invisible DIV within a visible DIV. See these two threads on it.
http://forums.asp.net/t/1489399.aspx
http://forums.asp.net/t/1479689.aspx?PageIndex=2

Resources