Using Durandal and KendoUI together

If you haven’t heard about Durandal you should really check it out. It is a great Single Page Application (SPA) framework written by Rob Eisenberg. You can find more information here.

KendoUI promise to be “Everything you need to build fast HTML 5 apps” – but is mostly about a set of great UI Controls.

For business applications that needs advanced UI controls I think KendoUI and Durandal can be a perfect match.

In theory it is not a problem to combine KendoUI and Durandal, but the KendoUI user controls works best, in my opinion, if you combine it with KendoUI’s own MVVM framework. In that way you can keep your view and viewmodel/model code 100% separated. The problem is that Durandal depends on knockout for databinding (MVVM) – so then there is only two ways to solve this – either you have to make kendoui work together with knockout, or you have to make durandal work together with the kendo databinding framework.

The first option – to make kendo work together with knockout, is actually quite simple as there is already an open source library available that solves this: you can find that library here. But using that library is not a perfect solution, because it is not supported by Kendo. The Kendo support team will refuse to help out with eventual problems if you use the knockout-kendo library – and there is no guaranty that this library will be kept up to date with kendo in the future.

To make Durandal work with the Kendo data-binding framework is probably the best option,but it is a bit harder to do because Durandal depends heavily on knockout. Durandal automatically binds views and viewmodels together using knockout. It would be really nice if we could extend durandal to automatically do this binding also for other data-binding frameworks than knockout. Luckily Durandal is quite extendable, so I was able to come up with the following solution:

I concluded that removing the Durandal’s dependency on knockout was not a good idea so instead of removing the knockout bindings as the default binding I think it would be a good solution to be able to specify that some parts of a view should use another data-binding framework.

Something like this:

<section>
 <h2 data-bind="html: displayName"></h2>
 <form data-mvvm-framework="kendo">
   <label>First Name:<input data-bind="value: firstName" /></label>
   <label>Last Name:<input data-bind="value: lastName" /></label>
 </form>
 <div data-bind="compose: 'rambase/plugins/welcome/viewmodels/welcome'"></div>
</section>

The important part to note here is the “data-mvvm-framework” attribute on the form element. This is an attribute I have added, and the idea here is to tell Durandal to use Kendo data-bindings for the form element, while the rest of the view will use the default knockout data-bindings. It was quite easy to extend Durandal to work like this. The binding between a view and a viewmodel is finding place in a Durandal module called ViewModelBinder. Here the view and viewmodel is bound together using knockout. Luckily Durandal provides two exstension points  (hooks) for data-binding. It has a method called beforeBind and afterBind. By hooking into the beforeBind event I could add my own binding logic like this:


viewModelBinder.beforeBind = function (obj, view) {
    var kendoElements = $(view).find('[data-mvvm-framework=kendo]');
    $(kendoElements).wrapAll('<div data-bind="stopBinding: true"></div>');
    for (var i = 0; i < kendoElements.length; i++) {
       kendo.bind(kendoElements[i], obj.viewModel);
    }
};

This code will find all html elements with a data-mvvm-framework attribute set to kendo. For each of these elements it will bind the element to a viewModel property on the module. I my view there is only one element containing the data-mvvm-framework attribute, but I could have more than one if needed. There is one important line of code in this beforeBind method which needs a bit of an explanation, and that is line 3. Both kendo and knockout uses the data-bind attribute for data-binding, so when using the Kendo data-binding I need to prevent knockout from applying data-bindings on the same element. This line of code will wrap my element in a div which will cause knockout to just leave all child elements alone. When rendered to the browser it will then end up like this:

<section>
 <h2 data-bind="html: displayName"></h2>
 <div data-bind="stopBinding: true">
   <form data-mvvm-framework="kendo">
     <label>First Name:<input data-bind="value: firstName" /></label>
     <label>Last Name:<input data-bind="value: lastName" /></label>
   </form>
 </div>
 <div data-bind="compose: 'rambase/plugins/welcome/viewmodels/welcome'"></div>
</section>

“stopBinding: true” is not something knockout will care about by default, but you can very easily add this custom binding like this:

ko.bindingHandlers.stopBinding = {
   init: function () {
      return { controlsDescendantBindings: true };
   }
};
ko.virtualElements.allowedBindings.stopBinding = true;

You can read more about this trick here: http://www.knockmeout.net/2012/05/quick-tip-skip-binding.html

By using the technique described above you can make Durandal work together with whatever data-binding framework you want – not just Kendo. 

If you don’t care about other data-binding frameworks, and just want Durandal to work as smooth as possible with the Kendo data-bindings the solution can be made simpler. Kendo knows that they are not the only javascript using data- attributes, and thankfully they have made it possible to use a seperate namespace for kendo data- attributes. In that way you can avoid conflicts with other libraries like Knockout (and many others). If you at the startup of you application add this line of code:


kendo.ns = "kendo-";

You will not use the data-bind attribute for data-binding, but instead data-kendo-bind. If I use a kendo namespace like this I don’t have to worry about conflicts anymore and my code can be much easier. I can then change my view code like this:

<section>
 <h2 data-bind="html: displayName"></h2>
 <form>
   <label>First Name:<input data-kendo-bind="value: firstName" /></label>
   <label>Last Name:<input data-kendo-bind="value: lastName" /></label>
 </form>
 <div data-bind="compose: 'rambase/plugins/welcome/viewmodels/welcome'"></div>
</section>

You can see I have removed the data-mvvm-framework attribute as I don’t need it anymore. The first name and last name fields are now bound using kendo, while the h2 element is bound using the default knockout binding. The compose binding will also work as expected, as it will use the knockout compose binding provided by Durandal.

I still have to apply the kendo data-binding in the beforeBind method, but now I can make it much simpler:

viewModelBinder.beforeBind = function (obj, view) {
    kendo.bind(view, obj.viewModel);
};

I now just bind the complete view to the viewModel – there is no need to just bind parts of the view with kendo, because I know that knockout and kendo will not interfere anymore. Now you can use the data-bind and data-kendo-bind together without any problems.

An easy way to save state in Silverlight and Windows Phone7

In many cases you need to save some state in your application. In Silverlight the best way to do this is to write to IsolatedStorage. After writing the same code many times for saving different types of objects to IsolatedStorage I started to look for a simpler/more generic way of doing it, and came up with a solution which makes me do like this:

//Write any object to IsolatedStorage
IsolatedStorageManager.WriteObjectToFile("aFileName",anyObject);

//Read any object back from IsolatedStorage
var objectFromFile = IsolatedStorageManager.ReadObjectFromFile<AnyClass>("aFileName");

This makes it very easy to write whatever object to IsolatedStorage. Below you can find my implementation of the IsolatedStorageManager

using System.IO;
using System.IO.IsolatedStorage;
using System.Text;

namespace IsolatedStorageSample
{
 public static class IsolatedStorageManager
 {
 public static void WriteObjectToFile<T>(string filename, T data)
 {
 string xml = Serialization.Serialize<T>(data);
 IsolatedStorageFile file = IsolatedStorageFile.GetUserStoreForApplication();
 using (IsolatedStorageFileStream writer = file.CreateFile(filename))
 {
 byte[] content = Encoding.UTF8.GetBytes(xml);
 writer.Write(content, 0, content.Length);
 writer.Close();
 }
 }

 public static T ReadObjectFromFile<T>(string filename)
 {
 string xml = null;
 IsolatedStorageFile file = IsolatedStorageFile.GetUserStoreForApplication();
 using (IsolatedStorageFileStream stream = file.OpenFile(filename, FileMode.Open))
 {
 using (StreamReader reader = new StreamReader(stream))
 {
 xml = reader.ReadToEnd();
 }
 }
 return Serialization.Deserialize<T>(xml);
 }
 }
}

The IsolatedStorageManager class depends on a class named Serialization which looks like this:

using System.IO;
using System.Runtime.Serialization.Json;
using System.Text;

namespace IsolatedStorageSample
{
 public static class Serialization
 {
 public static string Serialize<T>(T objectToSerialize)
 {
 if (objectToSerialize == null)
 return null;
 using (MemoryStream ms = new MemoryStream())
 {
 DataContractJsonSerializer serializer = new DataContractJsonSerializer(objectToSerialize.GetType());

 serializer.WriteObject(ms, objectToSerialize);
 ms.Position = 0;

 using (StreamReader reader = new StreamReader(ms))
 {
 return reader.ReadToEnd();
 }
 }
 }

 public static T Deserialize<T>(string json)
 {
 if (string.IsNullOrEmpty(json))
 return default(T);

 DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));
 T obj = (T)serializer.ReadObject(new MemoryStream(Encoding.Unicode.GetBytes(json)));
 return obj;
 }
 }
}

In order to get this to compile you need to add a reference to System.ServiceModel.Web

This code works great in both regular silverlight and in windows phone 7.

AutoCompleteBox in Windows Phone 7

Download sample source code

Windows phone 7 contains built in support for word prediction when a user types something in a TextBox. To enable this in your Textbox you have to set the InputScope to “Text” or “Chat”. If you create a TextBox like this:

<TextBox InputScope="Text" />

And starts to enter something in the TextBox you will see suggested words above the keyboard like you see below.

This is fine, and in many cases just what you need. But say for example you have an input field where you want your users to enter their favorite sport. Using InputScope Text or Chat is not the best option. If a user starts to enter “So” he will get a lots of words having nothing to do with sport – Doc, Six, Social, Society. The word “Soccer” which is the word the user most likely meant is not even on the screen, you will have to scroll to see it.

A solution to this could be to use a ComboBox (at least it could be a solution if it had been available for wp7), but in this case you have to define every sport you can think of when you write the application. But what if someone try to enter “Frisbee Golf” as their favorite sport. This is most likely not the first sport you think of when you sit down and make a list of sports, but it’s still someones favorite sport.

This is where the AutoCompleteBox from the Silverlight 3 toolkit is perfect. You can define all the sports you can think of. The user can select on of the already defined sports by just enter the first letters of the sport. If hes favorite sport is something you didn’t thought of, he can still enter it (but of course he wont get auto competition for that )

How to add an AutoCompleteBox to your wp7 application

  1. Add a reference to System.Windows.Controls.Input.dll (you have to browse for it – you find it where you installed the silverlight 3 toolkit) It is very important that you use the dll from the Silverlight 3 toolkit, as Silverlight 4 is not supported on Windows Phone 7.
  2. Add an AutoCompleteBox to your Xaml code and bind it to a list of words (a list of sports in my case). At this time the AutoCompleteBox works, but it doesn’t look good, as it is not styled like the other windows phone 7 controls. It also isn’t very touch friendly as the words in the list has to little space between the lines.
  3. Style the AutoCompleteBox to look like a wp7 control. See my sample code. The style is to long to include here.
  4. The control now looks good and is working. There is only one problem. If you select a word (a sport) from the list, the popup is not closed before you select it again. I read somewhere that this is a bug in wp7 and has nothing to do with the AutoCompleBox, but I can’t find it again, so I’m not 100% sure. Anyhow I have a really simple fix for this. On the SelectionChanged event I set focus to another control, this is normally what you want to do anyway. This closes the popup and the control works perfect.

Here you can see the final result both with the dark and the light theme

I have to thank Indrajit Chakrabarty for all help I got when I struggled with this. Blog: http://indyfromoz.wordpress.com/ Twitter: http://twitter.com/indyfromoz

Download sample code here