Showing posts with label ajax. Show all posts
Showing posts with label ajax. Show all posts

Monday, October 29, 2007

Webform_AutoFocus() before Sys.Application.Initialize()?

Recently I was developing an ASP.NET Ajax extender control which added behaviors when the target control gained focus. It was a custom implementation of an auto-complete control. Picture your standard auto-complete control but with multiple columns. So if you were to enter customer organizations you could enter by a system id, customer name or city where the customer is located. You could even enter a combination these attributes.

Anyway, if you've worked with the ASP.NET Ajax ScriptControl before you would know that you wire up your events within the initialize method, which you override from the base JavaScript "class". This allows the web browser to complete rendering of the page so all controls are created and properly registered before your code tries to use them.

However, I ran in to a bit of a snag when I tried to use the ScriptManager.Focus() method to set the focus to my target control upon first rendering of the page. I have a user entry screen where users can enter many records in sequence. So basically the users enter data in a few fields, hits submit to add the record and then the focus returns back to the first field, ready for the user to continue entering data.

The idea seemed solid to me, but I found out that the focus behavior wasn't working as I expected. I took a look at the rendered page and noticed that the Webform_AutoFocus() call which is created by the ScriptManager.Focus() runs prior to the Sys.Application.Initialize() call which calls my controls initialize! This means that my focus event handler has not yet been wired up, and there is no way for me to listen to the focus event.

Why is this? I can't think of a reason why the framework would want the focus to occur before initialize. Doesn't the name initialize even seem to imply that it would be the first function to run?

So I thought of a potential workaround. What if I could interrogate the target control to see if it currently has focus when I run the initialize method? It's not the prettiest solution, but it seems like it has potential. Unfortunately this hit a bit of a snag as well. After some research it turned out that IE has a property on the document known as activeElement which will provide the control which currently has focus. The problem? Only IE has such a property to tell me what control has focus, and I hate doing something which only works in a single browser.

Unfortunately I wasn't able to find any other workarounds, and as such only IE will appear to handle the system derived auto focus correctly. I suppose there are worse things to worry about. The control still works without listening to the focus event, it just works a little differently than I would like.

Microsoft, why couldn't you have just put the auto focus after initialize?

--John Chapman

Wednesday, October 24, 2007

ApplyStyleSheetSkin On System.Web.UI.Control?

I've been a big fan of the theme support which was added in ASP.NET 2.0, especially when I found the StyleSheetTheme property which lets me control at what time the skin values are applied.

Lately I've been building some reusable ASP.NET AJAX controls which are built by extending the ExtenderControl class which is a part of ASP.NET AJAX 1.0. I have been making reusable controls which serve a general purpose for the application I am working on. I like to make the control entirely configurable so I provide many properties which are settable by the consumer of that control.

I then wrap that control in a composite control with the control it extends and add context to this control. For example I may make a really cool auto complete type control and then make a composite control that understands my customer object. The composite control would include a textbox and the autocomplete ajax extender control. The control would also include information on how the list of customers should be filtered or anything else which is specific to the context of a customer.

Now, I've built many composite controls using these AJAX controls, but how do I define defaults for all of the controls? For example I want 250 millisecond delay for the AJAX control before making a web service request to filter what the user entered, how do I set this by default for all items on the site?

My first attempt was to make wrapper properties on the composite control that just exposed the child properties of the underlying autocomplete control. This works well, then I create one item in the skin of my active theme per composite control and away I go. This works, but it is areal pain, and it seems like there should be a better way.

I later stumbled upon the ApplyStyleSheetSkin method of the System.Web.UI.Control class. This looks perfect. I can call this method on my AJAX control which inherits from the ExtenderControl since ExtenderControl inherits from System.Web.UI.Control. This will be perfect. I'll just have to add one item to my skin file and then all composite controls can automatically share these defaults! What could be simpler? I can't believe I didn't know about this earlier.

So I give it a shot and see an error message saying the method only works on System.Web.UI.WebControls.WebControl! But then why put the method on System.Web.UI.Control? And why make no reference to it on the MSDN documentation? Meanwhile, I'm back to square one, making wrapper properties and duplicate entries in my skin file. Why all of the confusion Microsoft? This one makes no sense!

Yes I know I can just use IExtenderControl and basically build my own ExtenderControl which inherits from System.Web.UI.WebControl but that is a lot of logic I would prefer Microsoft worried about and I feel it shouldn't be necessary!

-John Chapman

Blogger Syntax Highliter