C# - Asp.Net : Update panel not updating in SignalR hub.on method - asp.net

I'm trying to add an item i receive from the server to a list in codebehind inside the SignalR hub.on method. After it gets added to the list, the update panel should update and show up on the front end. The item gets added to the list, but the updatepanel doesn't update. When i do a manual refresh of the page in the browser, then i can see the added item just fine. I also added a button to update the update panel after the hub.on method gets fired, and again it works fine. Just that when trying to update the updatepanel inside the hub.on method, nothing happens.
Note : The hub.on method is inside the Page_Load method.
This is the hub.on method :
SignalRService.ServerHub.On<string, string>("commandMessage", (param, param1) =>
{
if (param.Equals("addConnectedClient"))
{
string[] sUserDetails = param1.Split(',');
string sUserName = sUserDetails[2]; //The item i want to add
DEBUG_AddPendingUser(sUserName);
updatepanelusers.Update();
}
});
This is the aspx code of the updatepanel :
<asp:UpdatePanel ID="updatepanelusers" style="display: none;" runat="server" ChildrenAsTriggers="true" UpdateMode="Conditional">
<ContentTemplate>
<div id="userspending" runat="server" class="exercisepage pageleft"></div>
<div id="usersaccepted" runat="server" class="exercisepage pageleft2"></div>
<div id="usersdenied" runat="server" class="exercisepage pageright2"></div>
</ContentTemplate>
</asp:UpdatePanel>
Any help would be greatly appreciated! As i can't wrap my head around why this is happening.

Related

Unable to update label in update panel from user control ASP.net

My code is as follows.
<div class="table">
<asp:UpdatePanel runat="server" ID="labelPanel" UpdateMode="Conditional" >
<ContentTemplate>
<asp:Label Text="" runat="server" ID="Cost"></asp:Label>
</ContentTemplate>
</asp:UpdatePanel>
<uc1:ucPartsListing ID="ucPartsListing" runat="server" />
</div>
Now the usercontrol ucPartsListing itself has 2 update panels. There is an event fired from the user control to parent aspx for some conditions.
In that event, I am trying to set the label value which is present in aspx file. I am calling update manually from code-behind. Yet it doesn't work. Where am I going wrong ?
public partial class PartsEnquiry : BaseAuthPage
{
protected void Page_Load(object sender, EventArgs e)
{
ucPartsListing.OnQuotePartsItemSelect += new ascx.ucPartsListing.QuotePartsItemEventHandler(ucPartsListing_OnQuotePartsItemSelect);
}
void ucPartsListing_OnQuotePartsItemSelect(string price)
{
Cost.Text = price; //This is not working !
labelPanel.Update();
}
Set a breakpoint on your "void ucPartsListing_OnQuotePartsItemSelect(string price)" method and see if it gets hit at all.
I'm not sure what the user control is that you are using, but whatever control it is that is supposed to fire the event, try setting its AutoPostBack property to True.
I think you are out of luck with your current structure.
When the UpdatePanel inside you user control is fired in the browser, it will update the part of the page that is inside itself. You cannot update controls that are outside of the executing UpdatePanel.
Manually calling the Update() method on the outer UpdatePanel will not help since on the client it is still one of the inner UpdatePanels that is receiving the output back and updating the html tree.
To get it to work you will have to somehow trigger the outer UpdatePanel which will be able to update the Cost label.

How to correct ASP.NET webform jquery reference being lost on partial postback

Within an asp.net webform I have some jquery that controls the positioning of elements on the page. Since this is a webform and some of these controls talk to the server to get jquery to work I have the controls nested in an AJAX UpdatePanel to prevent postbacks from resetting my controls.
aspx:
<asp:UpdatePanel ID="searchupdatePanel" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<div id="searchholder" >
<div id="searchoptions">
Close Advanced Search
<br />
Filters
</div>
<div id="search" class="searchcontainer">
<asp:TextBox ID="tbsearchterm" CssClass="watermark" runat="server" OnTextChanged="tbsearchterm_TextChanged" />
<div class="buttons">
<asp:LinkButton runat="server" Text="Search" class="button search-big" ID="btnSearch" OnClick="btnSearch_Click" />
<asp:LinkButton runat="server" Text="Fx" class="button left big" ID="btnOperators" />
<asp:LinkButton runat="server" Text="Save" class="button right big" ID="btnSave" />
</div>
</div>
<div id="divAdvSearch">
</div>
</div>
</ContentTemplate>
</asp:UpdatePanel>
<div id="divBody">
<asp:UpdatePanel runat="server" UpdateMode="Always">
<ContentTemplate>
<div id="divSearchResults" visible="true" runat="server">
<uc:SearchResultsControl ID="SearchResultsControl" runat="server"></uc:SearchResultsControl>
</div>
</ContentTemplate>
</asp:UpdatePanel>
When the search button is clicked I modify the css class for the search control to reposition my search div layer which is the update panel "searchudpatepanel"
searchcontrol.js
$(function () {
$("#searchupdatePanel").addClass("searchmenubar");
$("#btnClose").hide();
});
$(function () {
$("#btnSearch").click(function () {
$(".searchmenubar").animate({ "margin-top": "5px" }, "fast");
$("#btnAdvanceSearch").show();
$("#btnFilters").show();
$("#btnClose").hide();
$("#divAdvSearch").hide();
alert("search");
});
});
The button click also calls serverside code to retrieve and populate the results within a user control called SearchResultsControl ( second update panel)
Where I am confused is when the searchResult Control is loaded with the results all references to the jquery classes are lost. As a result every div element that is hidden or button click that is called ceases to work. Working through this in debug I can see when the user control is called the Page_Load for the default.aspx file is invoked as second time. I assume this partial load is dropping reference to the js files I just don't know how to correct this.
I tried a test within the page load using IsStartupScriptRegistered to see if the js was getting called
string csname = "PopupScript";
Type cstype = this.GetType();
ClientScriptManager cs = Page.ClientScript;
if (!cs.IsStartupScriptRegistered(cstype, csname))
{
StringBuilder cstext1 = new StringBuilder();
cstext1.Append("<script type=text/javascript> alert('Hello World!') </");
cstext1.Append("script>");
cs.RegisterStartupScript(cstype, csname, cstext1.ToString());
}
Here on the initialization of the page I would see the pop up occur however when the UserControl was loaded I would pass through this a second time in the page load but the alert never displayed( I assume this is due to a partial load so the browser thinks the script is already registered).
The only other thing I can think of is I am overriding the rendering of the UserControl being loaded as it loads a custom result set.
protected override void Render(HtmlTextWriter htw)
{
if (IsPostBack)
{
QueryResponse qr = iu.GetSearchResults(SearchTerm);
int num = qr.TotalMatchesReturned;
SearchData sd = new SearchData();
htw.Write("<table style='width: 100%; height:100%'><tr ><td style='width: 50%'>");
htw.Write("<div id='divResultDetail' runat=server >");
htw.Write("<script type='text/javascript' src='../js/paging.js'></script><div id='pageNavPosition'></div><table id='results'>");
for (int i = 0; i < num; i++)
{
...edited for brevity.
Any suggestions or guidance as to why I am losing reference to the jquery functions? I am not using master pages so I haven't used the ASP ScriptManager.
This all worked fine prior to using UpdatePanels. I define "fine" as: the postback was reloading/registering the js files each time, so they were being reset (which was okay). However, now with some other changes needed I need to look at leveraging UpdatePanels.
Thanks for any suggestions or ideas.
You can use the live or delegate jQuery methods to get your handlers to be bound to any elements added to the page.
Alternatively, if you need some setup to always happen after every partial postback in addition to original page load, you can put it in a pageLoad method instead of document.ready. ASP.NET calls this on page load, and after every partial postback.
function pageLoad()
{
// Setup code here
}
Check this article for more:
http://encosia.com/document-ready-and-pageload-are-not-the-same/
You need to use delegate for the button click. It will assure that all elements present and future will be bound to the event handler.
http://api.jquery.com/delegate/
$("body").delegate("#btnSearch", "click", function () {
$(".searchmenubar").animate({ "margin-top": "5px" }, "fast");
$("#btnAdvanceSearch").show();
$("#btnFilters").show();
$("#btnClose").hide();
$("#divAdvSearch").hide();
alert("search");
});
You need to rebind the elements when the update panel finish updating. Like this,
var prm = Sys.WebForms.PageRequestManager.getInstance();
prm.add_endRequest(function () {
$('#add').click(function () {
});
$('#addPrevious').click(function () {
});
});
Hope this helps.

Cancel a cross-page postback?

I have a page that has several ListBoxes that have some cascading filtering based on the selected values using an AutoPostBack. The form takes all the selected values and generates an excel doc by cross-page posting to a different ASPX. The problem is, after clicking submit once, it will continually fire the cross-page postback every time a selection has changed.
<asp:ScriptManager runat="server" />
<asp:UpdatePanel UpdateMode="Conditional" runat="server">
<ContentTemplate>
<asp:ListBox ID="ParentItems" runat="server" SelectionMode="Multiple" AutoPostBack="true"></asp:ListBox>
<asp:ListBox ID="ChildItems" runat="server" SelectionMode="Multiple" AutoPostBack="true"></asp:ListBox>
</ContentTemplate>
</asp:UpdatePanel>
<asp:Button ID="Submit" runat="server" PostBackUrl="~/AnotherPageThatGeneratesAnExcelDoc.aspx" />
How do I cancel the cross-page postback from the ListBoxes' SelectedIndexChanged events?
Here's the event in the codebehind:
Protected Sub ParentItems_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles ParentItems.SelectedIndexChanged
'' do some filtering of the ChildItems ListBox
'' tried these but they do not work
''Submit.Enabled = False
''Submit.PostBackUrl = String.Empty
'' I also tried wrapping the button in a PlaceHolder and hiding/removing it, neither worked
''Buttons.Visible = False
''Buttons.Controls.Remove(Submit)
End Sub
This is my current solution using javascript. It works, but seems like a hack:
// using jQuery, add a click event that resets the form action
$("select[multiple]").click(function () {
this.form.action = this.form._initialAction;
});
Edit: adding a click event in the codebehind:
ParentItems.Attributes("onclick") = "this.form.action = this.form._initialAction;"
The problem is that using the PostbackUrl property resets the form action to a new URL, and your Ajax calls (or any subsequent postbacks) use whatever the current action of the form is.
Your solution doesn't work because the submit button isn't part of your UpdatePanel, so it never gets modified.
The easiest solution might be to move your Excel file generating code out of the page it's in, and into the page you're looking at, in the click handler of the button.
You also could probably include an iframe on the page you're looking at, and on submit, rather than going to a new page, set the source of the iframe to the Excel-generating page.
Both of these would avoid the need for using the PostbackUrl.

jQuery click disappears into some abyss

Here is my setup:
I have an asp.net button on a page --
<asp:Button id="btnSelectEmp" runat="server" Text="Select Employee" />
I have a .js file with the following jQuery click event --
$("input[id$='_btnSelectEmp']").click(function ($e) {
$("div[id$='_divEmpSearch']").css("display", "inline");
$e.preventDefault();
});
As you can see, clicking upon the button will set a div visible. Nothing special; not rocket science.
The div is wrapped with an asp.net update panel, and it contains an asp.net user control (.ascx)
<asp:UpdatePanel ID="UpdatePanel2" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<div id="divEmpSearch" runat="server" style="display: none;">
<uc:EmpSearch ID="ucEmpSearch" runat="server" />
</div>
// And a bunch of other controls that are updated according to whatever the user selects in the user control above
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="ucEmpSearch" />
</Triggers>
</asp:UpdatePanel>
The user control above is also wrapped in an asp.net update panel, because it has to communicate with the server. Among other controls like textboxes and such, the user control has two buttons upon it: 1) an asp.net button that does a postback and 2) an asp.net button that does an asynchronous postback.
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<asp:Button ID="btnSearch" runat="server" Text="Search" OnClick="btnSearch_Click" /
<br />
asp:Button ID="btnContinue" runat="server" Text="Select" OnClick="btnContinue_Click" />
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="btnSearch" EventName="Click" />
<asp:PostBackTrigger ControlID="btnContinue" />
</Triggers>
</asp:UpdatePanel>
The button in the user control that does a postback is working great. I click it, a postback occurs and my div control is re-hidden. I can then click on the Select Employee button (the one that I supplied the code for at the very first of the question) and the jQuery click event is handled and the div will be reshown.
However, the button in the user control that does an asynchronous postback works also, but after it hides the div, if I then click on the Select Employee button the jQuery click event will not be handled.
What this tells me is that for some reason during an asynchronous postback to the page, something happens to the Select Employee button so that the jQuery click event no longer happens. Why?
Your button is replaced with a new one when your update panel comes back with new content, so this:
$("input[id$='_btnSelectEmp']").click(function ($e) {
Binds to the elements it finds at that time, instead you'll want .delegate() or .live() here to listen for click events from current and future elements, like this:
$("input[id$='_btnSelectEmp']").live("click", function ($e) {
$("div[id$='_divEmpSearch']").css("display", "inline");
$e.preventDefault();
});
Or a bit cheaper using .delegate():
$("#container").delegate("input[id$='_btnSelectEmp']", "click", function ($e) {
$("div[id$='_divEmpSearch']").css("display", "inline");
$e.preventDefault();
});
In this case #container should be a parent of the update panel, one that doesn't get replaced in the postback.
Use the live() function. live() delegates the click event to a parent element, so the element (in this case btnSelectEmp) doesn't need to exist at the time the event is bound.
$("#<%=btnSelectEmp.ClientID%>").live("click" function ($e) {
$("#<%=divEmpSearch.ClientID%>").css("display", "inline");
$e.preventDefault();
});
What is happening is the btnSelectEmp button is getting replaced by the asynchronous call and the new element has not been bound to an event handler.
Also, I've modified the jquery selector here to use the exact client id of the element. This will improve speed, plus I seem to recall certain selectors don't work with event delegation in certain versions of Jquery.
try live('click', function(){...}) instead of click(function(){...})
Wild guess : "_btnSelectEmp" is used more than once?

FileUpload in FormView inside an UpdatePanel

The Scenario:
I have an ASP.Net webpage which I intend to use for letting the user(not the real users, but content manager basically) insert and edit the records in a table using a FormView. This FormView is inside an UpdatePanel, as I'm also using cascading dropdownlists to let the user select some values.
Now, this FormView also contains 4 FileUpload controls, and as you might know that these fileupload controls require a full postback since most browsers do not let Javascript access the disk. So, this problem would have been solved by doing something like:
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<Triggers>
<asp:PostBackTrigger ControlID="InsertButton" />
<asp:PostBackTrigger ControlID="UpdateButton" />
</Triggers>
<ContentTemplate>....</ContentTemplate>
</asp:UpdatePanel>
Edit: Forgot to add that the fileuploading takes place in the OnUpdating and OnInserting events of the SqlDataSource.
The Problem:
Since the InsertButton and the UpdateButton reside inside the Formview, I cannot directly access their ID's through markup. And MSDN says that:
Programmatically adding
PostBackTrigger controls is not
supported.
Please suggest some solution to make this work. Any insight on the matter is highly appreciated. Thanks.
P.S.- A workable solution for me was to set the UpdatePanel's PostBackTrigger as the whole FormView itself:
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<Triggers>
<asp:PostBackTrigger ControlID="FormView1" />
</Triggers>
<ContentTemplate>....</ContentTemplate>
</asp:UpdatePanel>
But now due to a bit of change in requirements, this solution(if you call it a solution) is not acceptable.
Have you given a though about using Iframe for doing the postback ? something like:
<iframe name="uploader" id=uploader
src="uploaderSender.aspx?AllowedExtension=<%= AllowedExtension %>&StoringPath=<%= StoringPath %>&StoringFileName=<%= StoringFileName %>&OldFileName=<%= OldFileName %>&MaximumSize=<%= MaximumSize %>"
width="450" height="50" frameborder=0 scrolling=no >
</iframe>
with uploaderSender.aspx like :
<form action="UploaderReceiver.aspx" method="post" enctype="multipart/form-data">
<input type="file" name="file" id="file" onchange="document.getElementById('IsFileUploading').style.visibility = 'visible'; document.forms[0].submit()"/>
<span id="IsFileUploading" style="visibility: hidden">
<asp:Image ID="Image1" runat="server" ImageUrl="~/immagini/Ajax-loader.gif" />
</span>
</form>
and UploaderReceiver.aspx like :
protected void Page_Load(object sender, EventArgs e)
{
//if there is one file to process
if (Request.Files.Count > 0)
//create the folder if it does'nt exists and returns the local path to get it
string StoringPathToBeSaved = StoringPath.GetFolderPath();
// append the name of the file to upload to the path.
StoringPathToBeSaved = StoringPathToBeSaved + StoringFileName + Extension;
Request.Files[0].SaveAs(StoringPathToBeSaved);
}
this is just bits of code just for you to figure out if you would be interested in this way of dealing with the upload, I can give you more if you want after.
see you, and good luck with your code,
Yay!! Finally got it to work!
Here's How:
Well contrary to what MSDN says, we can in fact add PostBack Triggers Programmatically. Not necessarily to the UpdatePanel, but to the ScriptManager.
After hours of playing around, here's what worked:
We are not able to access controls inside a FormView, untill the template has been rendered, so we can only add postback triggers after the formview's OnDataBound Event.
protected void FormView1_DataBound(object sender, EventArgs e)
{
if (FormView1.CurrentMode == FormViewMode.Edit)
{
LinkButton lb = (LinkButton)FormView1.FindControl("UpdateButton");
ScriptManager.GetCurrent(Page).RegisterPostBackControl(lb);
}
//Similarily you can put register the Insert LinkButton as well.
}
And now, if your UpdatePanel causes ConditionalUpdate, you can do something like this to make it work:
The Markup:
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>..
<EditItemTemplate>
...
<asp:LinkButton ID="UpdateButton" runat="server" CausesValidation="True" OnClick="Cause_PostBack"CommandName="Update">Update</asp:LinkButton>
...
</EditItemTemplate>
..</ContentTemplate>
</asp:UpdatePanel>
CodeBehind:
//call this function as the OnClick Event Handler for the Controls you want to register as
//triggers.
protected void Cause_PostBack()
{
UpdatePanel1.Update();
}
Otherwise, if your situation allows it(as mine does), just set the UpdatePanel's UpdateMode="Always"
This is old, but was trying to solve another problem and ran into this. This wasn't my problem, but here's an alternative for anyone new who runs into this as well.
You stated your problem as:
Since the InsertButton and the UpdateButton reside inside the Formview, I cannot directly access their ID's through markup
You actually can access their ID's through markup to use as the ControlID in the PostBackTrigger. You just have to use the button's name that is created in the page html mark-up as the ControlID. You can find the name created by viewing the page source when you're viewing the page in the browser. It typically is the name of the FormView + $ + name of the button.
For example, let's say you have a FormView named "FormView1" that contains an Insert button which you gave the ID of "btnInsert" during design. If you open up your page in the browser to view it live and then view the page's source, you'll notice that the html mark-up of the button will actually be given the name "FormView1$btnInsert".
Use that name as the ControlID in your PostBackTrigger and your update panel will work.
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<Triggers>
<asp:PostBackTrigger ControlID="FormView1$btnInsert" />
</Triggers>
<ContentTemplate>....</ContentTemplate>
</asp:UpdatePanel>

Resources