Wednesday, March 21, 2012

How To Handle OnChange / SelectedIndexChanged Type Event In JavaScript For The AJAX ComboBox

If you have ever used the AJAX ComboBox control and needed to interact with it client side in JavaScript, you will notice it's a bit of a different animal than it's ASP.NET server control counterpart: the DropDownList. If you want to get either the selected text or its value from a traditional DropDownList, all you needed to do was add an JavaScript function call to the 'onchange' client side property on the control like below:
<asp:DropDownList ID="AspNetDDL1" runat="server" AppendDataBoundItems="true" 
onchange="dropDownListOnChange(this);">
<asp:ListItem Text="( Select a Color )" Value="0" />
<asp:ListItem Text="Red" Value="1" />
<asp:ListItem Text="White" Value="2" />
<asp:ListItem Text="Blue" Value="3" />
</asp:DropDownList>
The JavaScript method for getting the value from an ASP.NET DropDownList is just as trivial as shown below. It will fire the alert each time a valid selection is made.
function dropDownListOnChange(sender) {
if (sender.value = 1) {
alert('You selected Red!');
}
else if (sender.value = 2) {
alert('You selected White!');
}
else if (sender.value = 3) {
alert('You selected Blue!');
}
}
However the AJAX ComboBox is a bit different and not just some user control inheriting from the ASP.NET DropDownList with all of the same properties and events. The AJAX ComboBox is built from the ground up, and when rendered to the client is comprised of (4) main parts:

- A text box showing the selected item.
- A button to press to show the list (usually a down arrow)
- An unordered list with all of the items bound.
- A hidden field with the selected value.

Now the common misconception is to try and handle client side events on the textbox or the unordered list like 'blur', 'keydown', 'keyup', 'change', or 'mousemove'. The problem is none of the events used individually or collectively (jQuery allows binding to multiple events easy) work perfectly. It requires the user to tab off the field, move the mouse, or some other action before the JS function gets called. That's not ideal at all as the selection from the ComboBox might be the only control on a page, or the last one on a page, and the client doesn't do any of the actions required. If for example the result of your wired up JS function is to show/hide other controls, then you want the JS function to fire immediately without delay and as it should.

The answer lies in some 'hard to find' documented events that can have functions assigned to handle these events. Specifically for this topic we are speaking of the add_propertyChanged event handler. We need to wire up this handler to our AJAX ComboBox client side which will then allow us to get the selected item or value client-side without having to make an expensive server trip. The documentation on the event handler is below:

Sys.Component.propertyChanged Event

As a side note, always keep this advice in mind. If you are a web developer and especially an ASP.NET webforms developer, it's all too easy to get lazy and inefficient by doing everything server-side. Why? Because you can! And how do we masquerade expensive server trips? With AJAX UpdatePanels, yeah! Don't get me wrong, I really like asynchronous postbacks with UpdatePanels and use them often, but make sure to use them when you actually need to go server side to make a call. If you make a dropdownlist, radio button, checkbox, or other server control go server side just to show another hidden row, add a control, or change some visual state, then you are bloating the time it takes to run your code and making a bad choice but not handling things that can take place 100% client side on the client. With all the JS explosion recently with libraries like jQuery there is no reason not to handle these types of needs client side.

Back on the AJAX ComboBox, we need to assign a function to the add_propertyChanged event handler on our control. Remember to get the ClientID of the value for server controls, as you cannot just pass in the raw ID.
function AJAXComboBox1_Change() {
//Add event to ui_ddlStrategicObjective AJAX Combobox:
$find('<%=AJAXComboBox1.ClientID %>').add_propertyChanged(function (sender, e) {
if (e.get_propertyName() == 'selectedIndex') {
//Gets the selected index from the HiddenField associated with the AJAX Combobox control.
var selectedIndex = sender.get_hiddenFieldControl().value;
////Gets the selected text from the AJAX ComboBox
var selectedText = sender.get_textBoxControl().value;

//Just sample JS code - you could do anything here:
//show/hide controls, alerts, change client settings, etc.
if (sender.value = 1) {
alert('You selected Red!');
}
else if (sender.value = 2) {
alert('You selected White!');
}
else if (sender.value = 3) {
alert('You selected Blue!');
}
}
});

//AJAX's pageLoad function automatically provides a handler for the 'load' event
function pageLoad() {
//Make call to handle selection changes to the 'AJAXComboBox1' AJAX Combo Box
AJAXComboBox1_Change()
}
Take notice above how we call our new function 'AJAXComboBox1_Change' in pageLoad(). You cannot interact with a control until it has been initialized (i.e. you cannot call add_propertyChanged on a control unless the control actually exists). A control does not exist until the initialization phase of the ASP.NET AJAX framework is complete. We can use AJAX's 'pageLoad()' method as this script needs to be ran during postbacks and partial postbacks is using UpdatePanels. The pageLoad function automatically provides a handler for the 'load' event. You can read about AJAX Client Events in the link below.

ASP.NET AJAX Client Life-Cycle Events

In conclusion there are a few 'big picture' points to make about this entry. First and foremost, when doing web development, try and make your applications as efficient as possible by doing operations client side that don't need to be done on the server (even if they can be done that way).

Second, the AJAX ComboBox may not be a widely used control going forward because its main draw which is the JS support for typing in values and quickly selecting them has been superseded in my opinion by things like the jQuery AutoComplete extender. Dropdowns in general are probably a good choice for the 1-25ish item range, but anything more bloats the page size. In this case making async callbacks to get values real time (like with the jQuery autocomplete) is a better idea. However, it does not mean there aren't a ton of apps already using the AJAX ComboBox, and the need to interact with it client side may present itself someday. If this 'someday' comes up (which it usually does), you will now be prepared to capture its values in JavaScript.

Wednesday, March 14, 2012

Get A Silverlight Control's Current Instance For Communicating Via The HTML Bridge

If you have a SilverLight control on an ASP.NET webpage, odds are eventually you will need to communicate with it, and this is done via JavaScript and the HTML Bridge. However you might find that the accessing the control's current state after user manipulation is not as straight forward as the documentation from the MSDN indicates.

In the MSDN and most examples, the suggestion is made that you explicitly register an instance of a scriptable type (your control's class) in the App class or the Page class. However there is a big difference on these (2) and also in the exact instance that you choose to register.

If in my control the main class is named 'MySLControl', so I decide to register its type in the 'Application_Startup' event of App.xaml like below:

Dim _MySLControl As New Silverlight.Custom.MySLControl
HtmlPage.RegisterScriptableObject("SLControl", _MySLControl)
The above will work perfectly and you will then be able to access your exposed <ScriptableMember()> types from JavaScript. However, there is a catch - the registered instance is a New instance of MySLControl so it will not contain the state of the control when called by JS.

So let's say you have a custom built online MP3 player you built with a 'Playlist' created by the user within the control. You want to use the HTML Bridge from your hosting ASP.NET app to communicate with the control and get some details on the playlist. If you access the registered control instance as coded above, you will not have access to any of the control's state after the user has interacted with it. Why? We registered a New instance and are not using the actual control's instance.

The change is (2) fold: First, move the registration of the type to a late event in the Page (control) itself like a wired up 'ControlLoaded' event as typical for many Silverlight controls. Second, register the current instance of the control and not a new instance. The code is displayed below:

Private Sub ControlLoaded(ByVal sender As Object, ByVal e As RoutedEventArgs)
'Register this control type so it can be accessible via JavaScript.
'This allows other platforms like ASP.NET to have a medium to communicate and raise events within the control.
'MUST use this instance or the current control state will not be accessible by the JS calling it via the HTML bridge.
HtmlPage.RegisterScriptableObject("SLControl", Me)
End Sub
The result? When you access your Silverlight control via JavaScript you will have access to the control in its current state including any interactions or manipulation done to the control by the client.

Thursday, March 8, 2012

Accessing Instance Properties in Silverlight from JavaScript

I have been messing around with the HTML bridge between Silverlight and JavaScript recently and have a few different posts on this topic that may help others. While those doing Silverlight are starting to see "the writing on the walls" as they say and may become the next technology to 'retire' akin to ActiveX controls from the IE4 days, it is still quite prominent as of this post so topics and discussion on it are well worthwhile.

There are several posts about exposing methods and properties to JavaScript from Silverlight so I will not get into that here. However most of the examples are really 'vanilla' as usual and don't offer more than the basic information.

One thing I wanted to do was access an instance property in Silverlight from JavaScript. There really is no major trick to it and it is as straight forward to access as it should be... for once.

So let's begin by looking at the exposed properties on the Silverlight control below. There is a simple 'String' and then an instance property of 'MyCustomClass' which is the focus of this post. Let's assume 'MyCustomClass' has (2) simple String properties on it: 'Name' and 'Address'.
<ScriptableMember()>
Public Property Description As String

<ScriptableMember()>
Private _MyClass1 As New MyCustomClass
Public Property MyClass1() As MyCustomClass
Get
Return _MyClass1
End Get
Set(ByVal value As MyCustomClass)
_MyClass1= value
End Set
End Property
Next we need to register our class to be accessible by script as well which is shown below. This can be done in the constructor of the control. 'Me' (or 'this' for C#) is my Silverlight control class instance behind the .xaml control.

HtmlPage.RegisterScriptableObject("MySLControl", Me)
Now you *might* think you need to register another member above for the instance property, but you do not need to do that. You can drill down to it through the main class instance exposed as a scriptable member as shown below:
//Get instance of the Silverlight File Upload Control
var SLControl = document.getElementById("SilverlightControl");
if (SLControl != null)
SLControl.Content.MySLControl.Description = "Blah";
//Drill down through the instance property exposed on the Silverlight control
SLControl.Content.MySLControl.MyClass1.Name = "Allen Conway";
SLControl.Content.MySLControl.MyClass1.Address = "123 Oak Street";
One thing to take note of - notice how I used a long hand property for 'MyClass1' rather than an AutoProperty. If you use an AutoProperty and can't provide an object that has been instantiated for its backing value by default or when setting its value, the JavaScript block will throw an error stating "Object reference not set to an instance of an object" when accessing the MyClass1 instance properties.

That's all there is to it. You can just drill down to the instance property through the registered instance of the scriptable type.

Wednesday, March 7, 2012

Upcoming Developer Events in Central Florida

There are several very nice events in the Central Florida area for developers in the upcoming months and 2012 year. The 1st (2) events below are *free* so there is no reason not to attend them if you are within a 50-75 mile range and are able to make it. The latter (2) are phenomenal conferences for the .NET and Microsoft Community and do have a registration fee, so see if your employer will put out for some training!





Orlando Code Camp: March 31, 2012 at Seminole State College, Sanford, FL.
This will be my 3rd year at CodeCamp and I have to say how impressed I am by the volunteers of the community to put on a 1st class event like this. It is every bit on par with a paid conference like VSLive and in fact has some of the same presenters like John Papa. If this is the only event you can attend in a year it will be well worth your Saturday. The event is free.





Windows Developer Camp: April 11, 2012 at the Royal Pacific Resort, Orlando, FL.
This touts itself as a Windows 8 event helping developers to get primed on technologies like Metro Apps, HTML5, JavaScript, XAML, and much more. The event is free and a meal is included.





Microsoft TechEd: June 11-14, 2012 at the Orange County Convention Center, Orlando, FL.
This is a premier Microsoft sponsored event for the development and IT industry as a whole. I have not attended the TechEd conferences before, but I know many of the elite in our industry do and it is sure not to disappoint.





Visual Studio Live!: December 10-14, 2012 at the Royal Pacific Resort, Orlando, FL.
This is a 5 day full conference that I have attended 4 times in the past. It does have a registration fee, but if you sign up early you can save money. Their site describes the conference best: "This event offers 5 days of over 60 educational sessions in tracks such as HTML5, Cloud Computing, Windows 8 / WinRT, and — of course — Visual Studio 2010+/.NET4+. Attendees receive a first-rate education, along with exclusive networking opportunities and one-on-one time with speakers that prepare them for what's now, new and next in the .NET development platform."


In addition to the live events above you can always check out the plethora of online training and content available from Microsoft below:

Microsoft Events

Tuesday, March 6, 2012

I Want To Run An Agile Project... Really I Do!

I had been meaning to speak briefly to Agile Project Management, so when I received some information in the mail today about the Agile Project Management Certification Workshop I knew it must be an omen or something.
As I have watched .NET mature over the last 10 years, and watch developers get more immersed in the technology that is not so "new" like it was in the early 2000's, a lot of focus has shifted to incorporating more advanced architectures like MVC, MVP, MVVM, and DDD and project methodologies like Agile. I personally think this is all great stuff, and am enjoying the whole community blossom and grow on a broad scale like never before.

Unfortunately where as implementing a new application architecture is a 'behind-the-scenes' decision not having a direct impact to the end client, changing the way we run our projects most certainly does. Enter Agile. This is not new either, but it is gaining acceptance in .NET shops and being used by my estimation at a rapid pace, and for good reason.

The "Waterfall" model or even Iterative development or "Mini-Waterfalls" still have their challenges, a lot of which I feel are solved by Agile Project Management. However as mentioned above attempting to run projects using Agile involves heavy participation by the customer and a paradigm shift in thinking. This change is not as difficult for software development teams as it is for the customers because we are technical and think methodically in nature so it is a good fit.

The abandonment of having that 'bulls-eye' finish date or being able to say "Here is what I want, see you in 6 months!" is too much to digest for many customers. I heard once that if anyone ever asks "When will the project be all done?", the response should be "Next year on May 24th at 2:38 P.M.." This in turn should make a question arise like, "Geeze, how do you know the time so preciously?", and in turn gets "Exactly, we can't and we don't provide that specific of a date."

Shifting from any type of traditional Waterfall to Agile takes total commitment and backing from both software development teams, management, and the customers. If any part of this commitment fails then it will probably not end up in success. As I heard at VSLive! and on some MSDN webcasts, try not to become a "We do Agile Scrum but, ...." team. There are no "buts", just commitment to doing it right. I hear this common theme often, and always present the question: "But how do we get Management and the Customers to buy into this shift in thinking and managing projects?" The answer: "Terrific question, and it's hard. There is no single answer to that." Magic and persuasion I suppose.

Truly technical shops or large IT organizations have probably already adapted Agile methodologies on the software development teams knowing of its success to creating high performance software development teams that are constantly communicating and delivering. However the less technical companies or ones that have a compressed management style used to having things done the old fashioned way will have an uphill battle implementing Agile.

Which leads me to the best part of this post. At VSLive! in Orlando last December the instructor of a TFS course shared a link on YouTube called "I want to run an agile project." It pretty much highlights perfectly the challenges associated with implementing Agile Project Management. If you are a software developer that has struggled with any of these challenges or have interest in Agile development, watching the link below offers a lot of head nodding and laughs. Super big thanks to the creators as they hit the nail on the head and presented this perfectly!


Friday, March 2, 2012

One Of A Thousand Possible Reasons For The "Invalid Postback or Callback Argument" Exception

The "Invalid postback or callback argument." exception in .NET can be caused by a slew of different reasons stemming from ASP.NET not being able to validate that a control event originated from the user interface that was rendered by that control. The most common solution offered as we all know is to set Page.EnableEventValidation = "False". Wrong! That's not a good idea from a security standpoint.

The better option is to determine what is causing the issue, and the bad news is debugging the code will not typically lead to the answer. You have to understand the code you have written and its relationship to this property to think about what you have done to cause this issue.

My most recent cause and solution? I made an update to a control outside the UpdatePanel housing a control that initiated the event, and 
redirected to another page from an ASP.NET menu after postback had completed. It immediately threw the "Invalid postback or callback argument" exception. The fix? Add the appropriate AsyncPostBackTrigger on the other UpdatePanel with the control being updated containing the event that is doing the updating. As soon as I did this, I was obeying all the good security rules and no need to set Page.EnableEventValidation = "False" which I never want to do as a lazy resort because I can't figure out what I did incorrectly.