Windows 8

.NET Musings

Wandering thoughts of a developer, architect, speaker, and trainer

NAVIGATION - SEARCH

Creating Custom Application Events in WinJS

Background

In my last post (Setting HTML Styles with Binding in Windows 8 WinJS Apps), I modified the style of the text on the page based on the values in a data model.  This worked great until the user chose to remove the Underline or the Italic styles.  Even though the model was indeed updated with the new values, the HTML page didn’t respond.

In order to correct this, I need to forcibly  remove the current styles and let the binding framework rebind the correct values.  This can be accomplished very easily with an Application event.

Related Posts:

This is part two of a series:

  1. Setting HTML Styles with Binding in Windows 8 WinJS Apps
  2. Creating Custom Application Events in WinJS (this post)
  3. Store and Share Settings in Windows 8 HTML/WinJS Apps

Creating an Application Event

The WinJS.Application namespace provides a lot of useful application level functionality, dealing with items such as activation, storage, and application level events.  In addition to responding to the application events (e.g. loaded, unload, ready, etc.), you can create a custom application event and add it to the event queue.  The syntax is simple, merely call WinJS.Application.queueEvent and pass in a simple object that contains at a minimum the type of the event.  Any additional properties will be available through the parameter that gets passed into the event listener function.

While the format of the object passed into the queueEvent method (beyond the “type” property) is completely up to the developer, to follow the undocumented standards, you should use “detail” as the parent property for the rest of the values to be passed into the function.

For example, to create an event when the TextSettingsChange and pass in that the setting that changed is the text weight, you can use this code:

WinJS.Application.queueEvent({ type: "TextSettingsChanged", detail: {value: "weight"} });

Listing 1 – Creating an event for changed text settings

Queuing Text Settings Changed Events

Remember from the previous post that even thought the model is Observable (and therefore the data-binding gets updated automatically), there is an issue with CSS/HTML that requires a little intervention.  The existing styles for Text Decoration and Font Style need to be removed before the changes will take affect.

The first step in fixing the problem is to make sure that the currently loaded page knows that the model has changed.  This can be accomplished by raising a custom application event for each of the changes.  The updated change methods are shown in Listing 2.  Note that for each change, a custom event is queued with the appropriate detail record.

setTextIsBold: WinJS.Utilities.markSupportedForProcessing(function (event) {
    if (event.currentTarget.winControl.checked) {
      Model.textSettings.textWeight = bold;
    }
  else {
      Model.textSettings.textWeight = normal;
    }
  WinJS.Application.queueEvent({ type: "TextSettingsChanged", 
              detail: {value: "weight"} });
}),
setTextIsUnderlined: WinJS.Utilities.markSupportedForProcessing(function (event) {
    if (event.currentTarget.winControl.checked) {
      Model.textSettings.textDecoration = underline;
    }
  else {
      Model.textSettings.textDecoration = normal;
    }
  WinJS.Application.queueEvent({ type: "TextSettingsChanged", 
              detail: {value: "decoration"} });
}),
setTextIsItalic: WinJS.Utilities.markSupportedForProcessing(function (event) {
    if (event.currentTarget.winControl.checked) {
      Model.textSettings.textFontStyle = italic;
    }
  else {
      Model.textSettings.textFontStyle = none;
    }
  WinJS.Application.queueEvent({ type: "TextSettingsChanged", 
              detail: {value: "fontStyle"} });
}),

Listing 2 – Updated Setters for the Text Settings

Responding to the Events

Now that the changes to the Text Settings are queuing the appropriate event with custom arguments, the currently loaded page needs to listen to and respond to the events.  Open home.js and in the ready event add the following line in Listing 3 to the ready event handler.

WinJS.Application.addEventListener("TextSettingsChanged",this.updateTextSettings);

Listing 3 – Adding the Event Listener

The updateTextSettings function isn’t created yet, but we will do that soon.  The reason to use a named function over an anonymous function is we want to disconnect the page from the event when the page is unloaded.  To do that, insert the following line into the unload event handler as shown in Listing 4.  I’ve included the entire event handler in case you are using an older template that doesn’t automatically add the unload event handler into the page control.

unload: function () {
  WinJS.Application.removeEventListener("TextSettingsChanged",this.updateTextSettings);
},

Listing 4 – Removing the Event Listener

The EventHandler Code

Create a property function on the page object named updateTextSettings.  This will serve as the Event Handler and will do three things:

  1. Remove the style for the contentContainer Div
  2. Remove the style for the MyTextArea TextArea
  3. Reprocess the binding statements

The first two are very straight forward.

this.rootElement.querySelector("#contentContainer").removeAttribute("style");
this.rootElement.querySelector("#MyTextArea").removeAttribute("style");

Listing 5 – Removing the styles

The final line is to reprocess the bindings.  We need to do this because the notification of the property change has already occurred, and the bindings were indeed updated.  The UI didn’t change because the CSS is being, well, persnickety.  So the final line of code in the updateTextSettings function is a call to WinJS.Binding.processAll, passing in null as the first parameter.  This will reprocess the entire page using the textSettings for the DataContext. The code for this is shown in Listing 6:

WinJS.Binding.processAll(this.rootElement, Model.textSettings);

Listing 6: Reprocessing the bindings

The complete code for the home page is shown in Listing 7:

ready: function (element, options) {
  MyTextArea.value = "Lorem ipsum dolor sit amet,"; //Shortened for brevity
  this.rootElement = element;
  WinJS.Application.addEventListener("TextSettingsChanged",
    this.updateTextSettings);
  WinJS.Binding.processAll(element, Model.textSettings);
},
unload: function () {
  WinJS.Application.removeEventListener("TextSettingsChanged",
    this.updateTextSettings);
},
updateTextSettings: function(e, z) {
  document.querySelector("#contentContainer").removeAttribute("style");
  document.querySelector("#MyTextArea").removeAttribute("style");
  WinJS.Binding.processAll(null, Model.textSettings);
},

Listing 7: The code for the home.js page object

Now, when you run the app, changing the Underlined and Italic properties to Off will remove them from the text on the page.

Summary

A very significant design paradigm in Windows 8 development is making sure your app is responsive and tasks are handled in an async manner.  One of the ways to make sure your application is responsive is by using events in a publisher/subscriber model. In WinJS, application events are a very effective (and easy) way to develop in an asynchronous way.

 

About the author

Philip Japikse

Philip Japikse Philip Japikse is an international speaker, a Microsoft MVP, INETA Community Champion, MCSD, CSM/ CSP, and a passionate member of the developer community, Phil has been working with .Net since the first betas, developing software for over 20 years, and heavily involved in the agile community since 2005. Phil works as a Principal Developer Advocate for Telerik, co-hosts the Hallway Conversations podcast (http://www.hallwayconversations.com), and is the Lead Director for the Cincinnati .Net User’s Group (http://www.cinnug.org). You can follow Phil on twitter via www.twitter.com/skimedic read his Telerik blog at http://blogs.telerik.com/skimedic and his personal blog at www.skimedic.com/blog.
 
Managed Windows Shared Hosting by OrcsWeb