Wednesday, March 28, 2012

Change Event not fired when changed once or more then restored to its original value.

Hi.


I am trying to ATLAS-ize an existing application with lots of Master Detail controls.

As I don't want to write a heap of new code I am using UpdatePanels rather than writing web services even though my situation is similar to the one in the CascadingDropDown example (http://atlas.asp.net/atlastoolkit/CascadingDropDown/CascadingDropDown.aspx)


The problem I have though is that if I change the master listbox selected value (say from 0 to 1) then the Update Panel refreshes fine.

If I change it back from 1 to 0 the SelectedIndexChanged event does not fire leaving a load of incompatible info in the details listbox

I'm assuming that this is because when the page was first loaded the value was 0 so it does not recognize that a change has occurred.

I'd be grateful for advice on the optimum solution to this.

Ah Problem Semi Solved!


The first thing I was doing "wrong" was that my page overrides Load and Save PageStateFromPersistenceMedium and stores it in a DB and just passes the GUID back and forth in a hidden field. This obviously means the ViewState updates never made it into my page.

I would appreciate some advice on things I can override to get this functionality back however as some of the ViewState is pretty huge but required without a lot of extra coding. Is their any way I can replicate what is happening automatically with __VIEWSTATE to my own custom hidden input (hdnViewStateId) (i.e. get it automatically submitted on a call back, get it passed back in the XML envelope and automatically update the value with the new one)

The other thing I was doing wrong was that I'd left in an old school Response.Write in my page which knackered up the XML sent! (By the way is there any way I could have switched on any error logging which would have alerted me to this last issue?)


Ah Problem Semi Solved!


The first thing I was doing "wrong" was that my page overrides Load and Save PageStateFromPersistenceMedium and stores it in a DB and just passes the GUID back and forth in a hidden field. This obviously means the ViewState updates never made it into my page.

I would appreciate some advice on things I can override to get this functionality back however as some of the ViewState is pretty huge but required without a lot of extra coding. Is their any way I can replicate what is happening automatically with __VIEWSTATE to my own custom hidden input (hdnViewStateId) (i.e. get it automatically submitted on a call back, get it passed back in the XML envelope and automatically update the value with the new one)

The other thing I was doing wrong was that I'd left in an old school Response.Write in my page which knackered up the XML sent! (By the way is there any way I could have switched on any error logging which would have alerted me to this last issue?)


Your drop down list is set to do a autopostback, correct? This would translate to a partial postback given that it's within the update panel.

Given that you've turned off the standard viewstate mechanism provided by ASP.Net, the "change" isn't going to be noticed 'cause the runtime can't compare what "was" (in the viewstate) with what "is" (in the form post). However, you can...

Take a look at this Fiddler trace of a site I quickly built using the update panel to do what you're doing with a drop down list (this is taken when the drop-down list auto posts back to the server):

POST /public/testsites/atlaswebsite3/Default.aspx HTTP/1.1
Accept: */*
Accept-Language: en-us
Referer:http://www.ben-rush.net/public/testsites/atlaswebsite3/
Cache-Control: no-cache
Content-Type: application/x-www-form-urlencoded
delta: true
UA-CPU: x86
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)
Host:www.ben-rush.net
Content-Length: 305
Proxy-Connection: Keep-Alive
Pragma: no-cache

ScriptManager1=myupdatepanel&__EVENTTARGET=DropDownList1&__EVENTARGUMENT=&__LASTFOCUS=&__VIEWSTATE=%2FwEPDwUKLTgwNzIyNjA5NA9kFgICAw9kFgICAw9kFgJmD2QWAgIDDxBkZBYBZmRkrJaJXj2KU%2FOTLiUUKLu7RDDJunM%3D&DropDownList1=2&__EVENTVALIDATION=%2FwEWBALyq5BnAp3kj%2BUKApKLpYsGApOLpYsGRIPIbgqWzDqL6Q8VoLqfhZnR%2BlM%3D&

You could grep out of the form post the object that created the postbck (__EVENTTARGET), and what its postback value is (DropDownList1=2). You could store the state of the last selected item value in whatever mechanism you choose and do your own compare, even in your custom page_load.

Thanks. I reckon that's probably the way to go.

I was contemplating (but probably wouldn't have actually done) a pretty horrible solution as I was playing with adding my own

__VIEWSTATE

hidden input with the GUID and it almost works if I strip out the extra "," that I get on the form post from the redundant ASP.NET added control of the same name!

I still hadn't sussed out how to change the XML envelope to reflect that change though..


When you say "change the XML envellop to reflect that change" you're talking about changing the XML response from the server that contains all the delta bits for the clientside framework, right (the XML that directs the client code to do its DHTML tricks to update the content within the UpdatePanel)?

So, before we go any further - your problem is that you can now detect when the change is made, but the atlas server code still doesn't and, therefore, doesn't include the right junk in the XML response back to the client to update the doodads in your UpdatePanel control?


Yes that's correct.

BTW: I've had a look at your blog and I suspect you're going to tell me that you know how to do this.

I'm a bit torn on the best way of doing this as.

I reckon__EVENTTARGET is probably the more robust way of doing it even though I lose a lot of the benefits of the ASP.NET module (I need to figure out how to store and retrieve the initial values of controls without using view state and raise the change events myself)

If I try and hijack the __VIEWSTATE control for my own purposes then a lot of the code is written for me already but my solution could break if a new version of ATLAS or update to ASP.NET comes out!


Actually Ben.

I've tried your suggestion and it's trickier than I thought it would be.

The problem is that when I select the original value in the Master ListBox nothing is sent back to the browser!

I assume that this is some sort of optimisation to only send back the things which are different and (as far as ASP.NET knows from looking at the old ViewState) it doesn't have to send anything back as they are the same.

It looks like I am going to need to integrate it with ViewState somehow. For the time being I've commented out my overrides and am sending all ViewState to the Client to get it working.

However I would be extremely grateful for suggestions of ways to get around this issue and get the benefits of both ServerSide ViewState Storage and ATLAS.


...let me dink around a bit with some stuff on my side here and try to duplicate what you're running into more accurately. This has got me curious about several things going on...


Can you visit this page and tell me how accurately this matches your situation:http://www.ben-rush.net/public/testsites/atlaswebsite3/.

I have a textbox and a listbox, the textbox updates its content to the selected index of the listbox when the selectedindex changes. The viewstate for the listbox is off. I don't believe that the listbox requires viewstate for identification of changes because the "change" will only occur when the index is changed; therefore a form post that includes the listbox as an eventtarget will be seen as a selectedindexchanged event. I could be wrong, but I seem to remember this being the case (I did some viewstate optimizations for a shopping cart system a long, long time ago).

Regardless, look at these two fiddler dumps, one during change from index 0 -> 1 (value 1->2), the other from 1->0 (value 2->1). Both show the value of the listbox.

POST /public/testsites/atlaswebsite3/Default.aspx HTTP/1.1
Accept: */*
Accept-Language: en-us
Referer:http://www.ben-rush.net/public/testsites/atlaswebsite3/
Cache-Control: no-cache
Content-Type: application/x-www-form-urlencoded
delta: true
UA-CPU: x86
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)
Host:www.ben-rush.net
Content-Length: 288
Proxy-Connection: Keep-Alive
Pragma: no-cache

ScriptManager1=myupdatepanel&__EVENTTARGET=ListBox1&__EVENTARGUMENT=&__LASTFOCUS=&__VIEWSTATE=%2FwEPDwUJNTA5MjUzOTYxZGTFj5uiiDfrPSUZQz6IYXNKpb8xOQ%3D%3D&ListBox1=2&TextBox1=0&__EVENTVALIDATION=%2FwEWBwKJvNCXBgK9ueOMCQKy1sniBQKz1sniBQKw1sniBQKx1sniBQLs0bLrBlpXNeow%2BdPC39h7%2F1FxYfamkoLm&

And the other...

POST /public/testsites/atlaswebsite3/Default.aspx HTTP/1.1
Accept: */*
Accept-Language: en-us
Referer:http://www.ben-rush.net/public/testsites/atlaswebsite3/
Cache-Control: no-cache
Content-Type: application/x-www-form-urlencoded
delta: true
UA-CPU: x86
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)
Host:www.ben-rush.net
Content-Length: 288
Proxy-Connection: Keep-Alive
Pragma: no-cache

ScriptManager1=myupdatepanel&__EVENTTARGET=ListBox1&__EVENTARGUMENT=&__LASTFOCUS=&__VIEWSTATE=%2FwEPDwUJNTA5MjUzOTYxZGTFj5uiiDfrPSUZQz6IYXNKpb8xOQ%3D%3D&ListBox1=1&TextBox1=1&__EVENTVALIDATION=%2FwEWBwKJvNCXBgK9ueOMCQKy1sniBQKz1sniBQKw1sniBQKx1sniBQLs0bLrBlpXNeow%2BdPC39h7%2F1FxYfamkoLm&


I should probably mention that I have a trigger in the UpdatePanel as well.

I suspect that it may be a trigger optimisation causing the issue (for the same reason as previously described it can't realise that there is a change to process so returns an empty envelope)

<Triggers>

<atlas:ControlEventTriggerControlID="drpMasterListBox"EventName="SelectedIndexChanged"/></Triggers>

Well yes that is definitely working.

Do you have a trigger?

Is your UpdatePanel set to the same options as mine or is anything different?

(I haveMode="Conditional"RenderMode="inline")

In any event I'm thinking of doing it without update panels now and using a custom extender.

I was hoping that UpdatePanels would be a quick and dirty solution but I'm not progressing as fast as I wanted to and I suspect I may hit yet more obstacles because my UpdatePanel is in a UserControl which I was planning to embed in another UpdatePanel at Page Level.


No, I don't have a trigger. I changed my rendering modes to what you have, and it didn't change things (I wouldn't expect that it would). You can visit the same page URL I gave you earlier to confirm.

If you have a control in your update panel that does a postback automatically (say, the listbox control with its autopostback option on), then you have no need for a trigger. Triggers will only be useful for controls that don't postback automatically. I haven't researched triggers much, but if they're anything like binding objects then the control they're bound to needs to be AJAX savvy anyway.

Try turning off the trigger, I guess - and see what that does.


MartinSmithh:

The first thing I was doing "wrong" was that my page overrides Load and Save PageStateFromPersistenceMedium and stores it in a DB and just passes the GUID back and forth in a hidden field. This obviously means the ViewState updates never made it into my page.

well, though i haven't tried it, i think it's safe to assume that your field will allways be maintained if you add it to the page by using the registerhiddenfield of the clientscriptmanager api.

No comments:

Post a Comment