Showing posts with label items. Show all posts
Showing posts with label items. Show all posts

Wednesday, March 28, 2012

LinkButtons programmically added to updatepanel click event not firing

I have a conditional updatepanel with a multiview control inside. The first view displays a list of items in a table with a linkbutton next to each one created programmically with an eventhandler for the click event. The click event changes the multiview's active view to the next view to display controls for editing that item. The item table's content is first initialized in the OnLoad() function inside a if(!isPostback). I plan to eventually have a save button in the second view that will update the table's content after that. (ScriptManager EnablePartialRender = "true").

Ex:

    for(int i = 0; i < itemcount; i++) { ... LinkButton itemedit = new LinkButton(); itemedit.Text = "Edit"; itemedit.Click += new EventHandler(itemedit_Click); table.Controls.Rows[i].Cells[1].Add(itemedit); ...}

When I view the page and click the linkbutton next to one of the items in the updatepanel it starts to update. However, the view never changes. Further tests have shown that the click event is never being handled. If I change the code so that the table is updated during initial load and postbacks, I can get the click event to fire once. After the multiview is goes back to the original view, the click event can no longer be raised until the whole page is reloaded.

So, what I am trying to figure out is how to create eventhandlers at runtime inside an updatepanel and getting them to fire on an update.

Well, I have found a solution. I desided to scale the problem down to the most basic functions by creating a test application containing an updatepanel, multiview control with two views, and some code in the background to create a linkbutton to switch from one view to the other. The page looks like this as generated by VS:

<%@. Page Language="C#" AutoEventWireup="true" CodeFile="dynamicevent.aspx.cs" Inherits="dynamicevent" %
<!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>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<atlas:ScriptManager ID="ScriptManager1" runat="server" EnablePartialRendering="True">
</atlas:ScriptManager>

</div>
<atlas:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<asp:MultiView ID="MultiView1" runat="server" ActiveViewIndex="0">
<asp:View ID="View1" runat="server">
view1</asp:View>
<asp:View ID="View2" runat="server">
view2</asp:View>
</asp:MultiView>
</ContentTemplate>
</atlas:UpdatePanel>
</form>
</body>
</html>

The page is pretty basic and so is the code behind:

public partialclass dynamicevent : System.Web.UI.Page{protected void Page_Load(object sender, EventArgs e) { LinkButton button =new LinkButton(); button.Text ="switch"; button.Click +=new EventHandler(button_Click);this.View1.Controls.Add(button); }void button_Click(object sender, EventArgs e) {this.MultiView1.ActiveViewIndex = 1; }}

This code creates one LinkButton to switch from ActiveViewIndex=0 to 1 and it works just fine. However, on a larger scale, creating a hundred or more LinkButtons next to records that must be requested from a database each time the page handles a postback doesn't sound like a good idea to me. So, I moved by button creation code into an if(!IsPostBack) block:

protected void Page_Load(object sender, EventArgs e) {if (!this.IsPostBack) { LinkButton button =new LinkButton(); button.Text ="switch"; button.Click +=new EventHandler(button_Click);this.View1.Controls.Add(button); } }
The changes break the page. When I click the LinkButton, the updatepanel reloads the contents of the first view minus the linkbutton. The linkbutton is lost and its eventhandler with it. So, perhaps atlas requires that everything remain wired up perfectly up until after Page_Load() is called at least. I did some thinking and came up with some code that fixes the problem by using the cache to store the button to be rewired on the next postback. It appears that that is all the work I need to do to get my click handler to work. I think the benefits are significant enough although it is hard to see in this example: protected void Page_Load(object sender, EventArgs e)
{
if (!this.IsPostBack)
{
LinkButton button =new LinkButton();
button.Text ="switch";
button.Click +=new EventHandler(button_Click);

this.View1.Controls.Add(button);
Cache.Insert("test", button);
}
else
{
((LinkButton)Cache["test"]).Click +=new EventHandler(button_Click);
this.FindControl(((LinkButton)Cache["test"]).Parent.UniqueID).Controls.Add(((LinkButton)Cache["test"]));
}
}

The code rewires the event handler during a postback. The Control.Parent .Controls.Add() does not work directly for the LinkButton in the cache but the FindControl() method works just fine. I believe that although they have the same name, the first parent of the LinkButton is not the same as the second one. I am new to ASP.NET v2 and Atlas but I do not remember coming across this problem in the past with .NET 1.1.

If anyone has a better solution, please let me know. At this moment I am facing writing some manager class to wire up all my eventhandlers on on each postback and I really would like a better way.


changed

this.FindControl(((LinkButton)Cache["test"]).Parent.UniqueID).Controls.Add(((LinkButton)Cache["test"]));
to
this.Controls.Add(((LinkButton)Cache["test"]));
and it works just fine. This means that it does not matter where the LinkButton is located, just that it is added back to the page.

Thanks a lot for the solution you posted. I have been facing the same problem and your solution worked for me. But, I wonder if there is some other solution to this issue. If I find any I will post it here.

Thanks again.


Yes, that's not specific to Atlas. Any control that's added dynamically to the control tree must be added back on every subsequent postback.

I came across another issue when I was working with this yesterday. What I saw was that after a few postbacks my dynamically added link buttons won't work in fact it threw an object required error. Reason, they were removed from the cache and hencethis.Controls.Add(((LinkButton)Cache["test"])); would not work.

So, I tried to check if the cache had the button in it and only then I would execute this statement else I would create new linkbuttons. But guess what, I got back to the same problem I started off with. The button would not fire the event.

In the solution we completely depend on the cache to make sure that the linkbuttons are wired to the respective events. What would happen when the buttons are removed from the cache for whatever reason, especially in a production environment?


Ok, I think I may have a solution for this...as bleroy indicated this is the default behavior with dynamically added controls (that you have to add them to the page on every postback). So, if you add the linkbuttons to the page on Page_Init instead of Page_Load, you will not have to worry about caching them in order to re-wire the controls with the events.

Let me know if this was helpful.


I'd like to respectfully point out that putting a control in the cache is a bad, bad, bad idea and you should never ever do it. One reason is that this maintains an in-memory reference to the instance of the control, hence to the corresponding instance of the page and thus to a huge object graph that should have been thrown away at the end of the request. There is no way this is not going to blow up whenever you get more than a few simultaneous requests.

You should only put data (that is, disconnected data) or output (i.e. strings) in cache...

ListBox - SelectedIndexChanged Problem

I have a data bound ListBox. When I click on an item it fires the SelectedIndexChanged event like it should, however, NONE of the items are marked as 'selected' in the event method. Any ideas?

Doh! Found the solution! I was rebinding the data to the listbox on postback and apparently this is what was causing the problems. I wrapped the data binding code in an IF statement that executes if IsPostBack is false.

This might be good to know for others out there.

Monday, March 26, 2012

ListBox does not preserve selected items after using UpdatePanel

Hi there,

I have a ListBox with Multiple Selection feature. After I click the Button on the form, I should process the selected items in the ListBox. The code works fine but after I add the ListBox in an UpdatePanel, it does not preserve selected items.

Any suggestions?

Thanks,
Mosh

use hidden fields.
function addItemstoHiddenField(){
var lbPlantDest = document.getElementById("lbPlantDest");
var lbSalesDest = document.getElementById("lbSalesDest");
var lbPlantDest = document.getElementById("lbPlantSrc");
var lbSalesDest = document.getElementById("lbSalesSrc");
var hdnPlantAccess = document.getElementById('hdnPlantAccess');
var hdnSalesAccess = document.getElementById('hdnSalesAccess');
var hdnPlantAccess = document.getElementById('hdnSrcPlantAccess');
var hdnSalesAccess = document.getElementById('hdnSrcSalesAccess');
for (i = lbPlantDest.options.length - 1; i >= 0; i--) {
hdnPlantAccess.value = hdnPlantAccess.value + lbPlantDest.options[i].value + ',';
}
for (i = lbSalesDest.options.length - 1; i >= 0; i--) {
hdnSalesAccess.value = hdnSalesAccess.value + lbSalesDest.options[i].value + ',';
}
for (i = lbPlantSrc.options.length - 1; i >= 0; i--) {
hdnSrcPlantAccess.value = hdnSrcPlantAccess.value + lbPlantSrc.options[i].value + ',';
}
for (i = lbSalesSrc.options.length - 1; i >= 0; i--) {
hdnSrcSalesAccess.value = hdnSrcSalesAccess.value + lbSalesSrc.options[i].value + ',';
}
}

Listbox selections to update secondary listbox items

Good Afternoon,

I am extremely new to the Atlas functionality, and am trying to address some customer requests using Atlas. Two listboxes, Category and SubCategory, are initially rendered on the page with all distinct values. My question is how to update the SubCategory listbox when items have been selected in the Category listbox. I have tried to include a parameter for the selection of the SubCategory items, but the list initially is rendered with no items since the parameter value is not assigned.

Any help, insight, or suggestions is greatly appreciated. Also, any suggestions on best practices is also welcome regarding controls utilizing Atlas (for example, using a dataset to populate the listbox versus going directly against the SQL tables).

Thank you,

Erik

Hi,

It sounds like the CascadingDropDown control in this toolkit may be the answer to your questions.

http://atlas.asp.net/atlastoolkit/CascadingDropDown/CascadingDropDown.aspx

Regards


Thank you for the response. Is there any way to utilize a listbox instead of a drop down? Currently, the users can select multiple items from the list.

Hi,

Could you initially populate the subcategory box in the page_load event (when not Page.Ispostback), then have the list updated with a control event parameter on the Category Listbox.

Hope this helps

ListSearch with ~15,000 items under dropdownlist

I have a dropdownlist with around 15,000 items, which can be quite irritating for a user to select the right item.

So, I put in ListSearch to facilitate the selection process, but now I'm noticing that there's about 5 second delay from the moment I start typing the first few characters of the item and the time I actually see the typed characters below my dropdownlist. And 5 seconds is way too long of a delay!!

When I tried the same ListSearch on a dropdownlist with a fewer number of items (say...about 100), then it worked instantaneously.

Has anyone seen similar problem? And how can I make ListSearch work faster?


Thanks.


Hi,

The ListSearch delays any processing until the first time the user starts typing. This is by design (on a number of our components) because if you put a few dozen components in a repeater you don't want them to all do their processing at once when the page loads. I'm a little skeptical that you really want to put 15,000 items in a drop down (instead of providing a search/results selection UI with something like modal popup), but you could probably tweak the ListSearch beahvior pretty easily to start processing the items in its initialize function.

Thanks,
Ted


I agree with you. Putting more than 15,000 items under a dropdownlist is an overkill, but I'm currently migrating our old ACCESS application to ASP 2.0 and it is required to stay with the same dropdown control. Apparently, ACCESS's version of dropdownlist can handle 15,000 items and has the capability of search incrementally. So, I'm kinda stuck with a dropdownlist here. :-(

I guess the users don't want to go through few more clicks with the search/results selection page.


With that aside, what did you mean by "tweaking ListSearch"?? Would you be able to show me an example or direct me to some website where I can look into?

Thanks for your help.

-Brian


Hi,

Get the full source version of the Toolkit and look at the AjaxControlToolkit\ListSearch\ListSearchBehavior.js file. You can experiment with moving the _isSorted check (line 242) from _onKeyDown to initialize (remember to rebuild when you change one of the scripts as they're embedded resources). I think this would help fix the delay you're seeing the first time a user accesses the list.

Thanks,
Ted


Thank You!


I've written a blog post explaining how you can alter the ListSearch Extender to speed up the initialization by giving it a hint as to whether the target list is sorted or not. It is the determination of whether thie list is sorted or not that takes a long time.

http://damianblog.com/2007/06/19/speeding-up-listsearchextender/

If there is enough interest, I'd be happy to add the changes to the control toolkit.


Thank you for this. I will definitely take a look at this and hopefully I'll get the ListSearch Extender to work faster.

-Brian

ListView Chunky Refresh -- Bug or Feature?

Currently the ListView re-renders itself in chunks of 5 items. Meaning that if you had a ten items in your list the control would be rendered twice: once after 5 items and again after 10. This is hard-coded in Atlas.js on line 10271. (see code below.)

Right now I am using the ListView to generate an html table and the refresh is rather clunky and unattractive. I would rather have the entire table refreshed in one go. Does anyone have any suggestions?

// Atlas.js:10271
// note the hardcoded "5"
var lastElementToRender = Math.min(itemLength, _currentIndex + 5);
for (; _currentIndex < lastElementToRender; _currentIndex++) {
var item = _data.getItem(_currentIndex);
// items added to DOM, then rendered
}

Nick Schrock

CareEvolution RHIO Technology PlatformCareEvolution

hello.

i've noticed that too. open a request and ask for a property which let's you influence the number of items that are to be generated,,,