25 March 2012

Instant language update in a Windows Phone 7 application using MVVM

With more and more Marketplaces being added to the Windows Phone ecosystem, globalization of your app becomes all the more more important. I am happy to see a lot of apps these days support multiple languages. I usually employ a solution described in my article MVVMLight based language selection for Windows Phone 7 – this automatically picks up the language from the phone and defaults to English/US if the default language is not supported by the app. But I also like to give the user the chance to override the automatically selected language. I, for instance, run the phone OS in English/US, but I’d like specific Dutch apps to run in Dutch, thank you. If you follow the globalization example as described by MSDN using my code, that unfortunately requires the app to be restarted after applying the language change. Well, no more!

The sample as provided by MSDN provides a localized string helper that looks more or less like this:

namespace InstantLanguage.Resources
{
  public class LocalizedStrings
  {
    public LocalizedStrings()
    {
    }
  
    private static AppResources localizedResources = new AppResources();

    public AppResources LocalizedResources 
    { 
      get { return localizedResources; } 
    }
  }
}

I employed it since my first localized app, and I usually put it in the same directory as my resource files. You declare it in your App.xaml like this:

<Application.Resources>
    <!-- More resources -->
    <Resources:LocalizedStrings x:Key="LocalizedStrings"/>
</Application.Resources>
Of course you need to declare the namespace for LocalizedResources first, so in the top you will add something like
xmlns:Resources="clr-namespace:InstantLanguage.Resources"

And now you can use it to show localized strings by binding to it like this:

<TextBlock x:Name="ApplicationTitle" 
  Text="{Binding LocalizedResources.AppTitle, Source={StaticResource LocalizedStrings}}" 
  Style="{StaticResource PhoneTextNormalStyle}"/>

But unfortunately, as I said, if you change the language, for instance by calling this code, nothing happens.

Thread.CurrentThread.CurrentUICulture = new CultureInfo("de-DE");
Thread.CurrentThread.CurrentCulture = Thread.CurrentThread.CurrentUICulture;

The reason for this is pretty simple: the app has no way of informing the GUI, as LocalizedStrings has no support for INotifyPropertyChanged. But that can be easily fixed, by taking MVVMLight and implement LocalizedStrings as a child class of ViewModelBase:

using System.Windows;

namespace InstantLanguage.Resources
{
  using GalaSoft.MvvmLight;

  public class LocalizedStrings : ViewModelBase
  {
    private static AppResources localizedresources = new AppResources();

    public AppResources LocalizedResources
    {
      get { return localizedresources; }
    }

    public void UpdateLanguage()
    {
      localizedresources = new AppResources();
      RaisePropertyChanged(() => LocalizedResources);
    }

    public static LocalizedStrings LocalizedStringsResource
    {
      get
      {
        return Application.Current.Resources["LocalizedStrings"]
            as LocalizedStrings;
      }
    }
  }
}

and then there is another matter: the app needs to have a way of kicking off the RaisePropertyChanged event on a class used as a StaticResource. That’s what UpdateLanguage and the static LocalizedStringsResource are for. Note that for this to work, you will need to have defined the resource with the key LocalizedStrings:

<Resources:LocalizedStrings x:Key="LocalizedStrings"/>

The keys that need to match are marked in red in both pieces of code. Anyway, after you changed the language, call:

LocalizedStrings.LocalizedStringsResource.UpdateLanguage();

And boom – all your texts coming from the resource file will update instantaneously.

InstantLanuage

Here you can find a sample solution demonstrating this principle using the newest release of my #wp7nl library on codeplex and the technique I mentioned earlier. There’s a simple viewmodel subclassing LanguageSettingsViewModel, and you can see the call to UpdateLanguage directly after the language setting has been changed:

using System.ComponentModel;
using InstantLanguage.Resources;
using Wp7nl.Globalization;

namespace InstantLanguage.ViewModel
{
  /// <summary>
  /// Main view model. By subclassing LanguageSettingsViewModel we get properties 
  /// "SupportedLanguages" and "CurrentLanguage" for free. 
  /// </summary>
  public class MainViewModel : LanguageSettingsViewModel
  {

    public MainViewModel()
    {
      // Note: en-US is added by default
      AddLanguages(new Language 
	    { Description = "Deutsch", Locale = "de-DE" });
      AddLanguages(new Language 
	   { Description = "Nederlands", Locale = "nl-NL" });
      PropertyChanged += MainViewModelPropertyChanged;
    }

    void MainViewModelPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
      if (e.PropertyName == "CurrentLanguage")
      {
        SetLanguageFromCurrentLocale();
        LocalizedStrings.LocalizedStringsResource.UpdateLanguage();
      }
    }
  }
}

In the end, it’s always pretty simple.

Note that for this globalization and the code to work properly, you will need to take into account the following:

  • You will need to change the “Custom Tool” property for each resource file to “PublicResXFileCodeGenerator” (default is ResXFileCodeGenerator)
  • You will need to have a .resx file for every language you support. For the default language I call mine usually AppResources.resx, for German I then have to define AppResources.de-DE.resx, etc.
  • You will also need to add supported extra languages in the SupportedCultures tag in your main project. You need to do manually, by opening the project file in for instance notepad. Why this can’t be done from Visual Studio – don’t ask me, I’m just the messenger here ;-). To support Dutch and German for instance you change the tag’s contents to:
<SupportedCultures>nl-NL;de-DE</SupportedCultures>

Note: I got the idea from a gentleman I met at the 2012 edition of the Microsoft Techdays in The Hague while while I was manning at the Ask The Expert stand. He showed me it could be done, but did only briefly showed me some of code and certainly not all of it. Once I knew it could be done, I more or less pieced this together in the moments I was not being bombarded by questions from developers dropping by. Unfortunately I don’t remember the gentleman’s name, or else I would have added some credits.

Have fun! I hope this helps you storm the new Marketplaces! ;-)

04 March 2012

MVP Summit 2012–the day after

So here I am, back in the Netherlands, after the MVP Summit 2012, still quite dazed from what hit me. It was my very first summit, and I was not quite sure what to expect. In retro respect the most amazing thing was what might be called ‘super Tuesday’. I spent a whole day with my fellow Windows Phone MVP’s and the product team. Suddenly all the people I only conversed with on twitter or live messenger were in one room: people like Ginny Caugey (I finally now know how to pronounce her last name), Matt Hidinger, Den ‘DennisCode’ Delimarsky (he actually is recognizable from his XBox avatar), Atley Hunter (who I think deserves the nickname ‘Fast Forward’) , Nick ‘ActiveNick’ Landry, Peter Novak, Rudy Huyn, to name just a few – and we where joined by people of the product team, which included Cliff Simpkins, Ben Lower and a few more whose name I omit because I am not even sure if I can mention them without spilling some beans. I feel a bit lame about this, but I like to err on the side of caution. For I must admit that when I got the award and was requested to sign an NDA documents it felt a bit over the top because frankly, I haven’t been seeing very much that required NDA for since October. Up until that remarkable Tuesday. I cannot go into any detail, other than that it was somewhat of a bewildering experience. For obvious reasons Microsoft are keeping their cards very close to the chest about anything related to Windows Phone, and this was quite different. To say the contents were interesting is like calling Mount Everest a ‘pretty steep hill’. After the formal sessions there was also an off-site event, which was at the Lucky Strike Lanes in Bellevue, where we got to know each other in a more informal way. I am still not sure who are the loudest, Canadians or Michiganians, but they give each other a run for the decibels ;-)

Another interesting observation I made during some sessions over the week was related to the recent row on the internet about MVP’s being Microsoft “marketing puppies”. Let me tell you this: behind doors, Microsoft asks for feedback and boy, do they get feedback from their MVP’s. A lot of typing and/or scribbling is being done while this is going on. Debates sometimes get pretty heated, but the setting is always a polite, frank exchange of ideas. Microsoft listens, listens intensely, and not only this occasion. But I feel a lot depends on how you put it in words. Think about what you would like to achieve before you spill your frustrations in a four-letter-words rant on the internet next time.

So what did I take from this occasion?

  1. A lot of solid information. I was told this differs from product group to product group; Windows Phone being pretty new and making aggressive movements forward, inherently is a hot spot where a lot is going on.
  2. Faces, names, and contact cards. It’s unbelievable how much people you meet. Being open to others is a natural things amongst most MVP’s – or else you would not be an MVP in the first place – and conversations start pretty easy, even for people who are bit contact shy like me. And it’s unbelievable how, in this time of online living, things are still different after you have shared a drink or talked a couple of hours into the evening. Apart from the people I mentioned above I met Rene Schulte, Laurent Bugnion, Scott Guthrie (thanks Laurent!), Scott Hanselman (sorry I pretended mixing you up with The Gu ;) ), Micheal Crump (he does exist, and I have pictures to prove it), Morten Nielsen, András Velvárt, Dave Bost, Chris Koening (both Windows Phone 7 DPE, equivalent to our own Matthijs Hoekstra), Davide Zordan (thanks for the Win8 copy!), David 'Wynapse' Campbell and I finally got the see our expertise group contact Tracey Hackney. They now have faces and voices. That still counts.
  3. Too little sleep, a crumpled back from spending too much time in a cramped aircraft chair and if I am not mistaken, a severe cold or a flue in development ;-)

Simply put: this was definitely worth the trouble.

Now that I’ve had - and survived ;-) - my first Summit, I think I have some advice for next-time-newbies:

  1. Try to get into one of the ‘central’ hotels: Hyatt, Westin, Silver Cloud or Courtyard. The other hotels are hotel-wise just a good but a lot more away from the ‘action’. Microsoft organizes a good shuttle service – but that stops at 9pm and I can assure you most times you are not done at that time. And then you have to get a cab or something.
  2. When you need to be on the campus early in the morning, allow for an hour travelling time. It’s actually more like 20 minutes, but you have to allow for traffic jams or the fact that the bus sometimes needs to take a tour along other hotels. And you do want to be on time. Some people weren’t in time for some special event organized by our Dutch MVP lead and simply missed it. Set an alarm clock, take a strong coffee (or tea) and get outta there.
  3. There’s usually a first-timers event early on the first evening. I found it useful to drop by. There were some Microsoft people and seasoned MVP’s talking with us newbies to get us in the mood. On the practical side, there’s food as well.
  4. Prepare. The Schedule Builder is sometimes confusing and I ran into a problem getting the app on my phone to run, which I only noticed being on-site. Hook up with some seasoned MVP’s up front and ask advice as to which side sessions and/or side parties to go to. I did not, and I missed a few things because of that.
  5. Download the MS Campus Maps app on your Windows Phone. It’s indispensible for getting around and getting directions.
  6. Download My ContacTile  on your Windows Phone – it creates a QR code of your contact info to quickly share via Bing Vision.
  7. Hotel rooms are for storing suitcases, taking a quick shower and some essential sleeping. That’s all. Don’t spend time there. Although most expenses during the Summit are covered I think I paid about €800 to fly to the USA and stuff so I made sure I got the most out of it. I figured I would pay the fatigue price later (like now :-) ).
  8. Bring power. Have a charger with you all the time and/or buy yourself a simple ‘USB juice pack’. It’s also a great way to help out fellow MVP’s who did not bring one, so they can borrow yours. A great conversation starter if any.
  9. When you are in a shuttle bus and get to sit next to a stranger, or at the breakfast room: introduce yourself and talk. Ask after their expertise and what they are working on. I was able to help out two people by showing them a blog post I wrote.
  10. The attendee party is big and spectacular and usually the last occasion to meet everyone. Do go there and have fun.
  11. Especially on the first days you want to be sharp. Keep down the booze and try to get a least some sleep.
  12. Keep your NDA. Watch your use of social media. Don’t discuss things outside your product group or in public places. The hardest part is not to correct incorrect speculations or react with body language ;-). I resorted to “I’d rather talk about something else now” at one point. It made me respect the product group members who have to make this mental juggle all the time very much.

Some special advice to MVP’s from outside the USA:

  1. Make sure you have enough cash on you to be able to tip people. That’s what you do in the USA. Familiarize yourself with the unwritten rules. 10% is ok, 15% if you are really satisfied. Cafeteria and such sometimes don’t expect a tip to be handed over directly but then there is usually a kind of can where you can drop the change. It’s not always obvious to me.
  2. Even more important: make sure you have a credit card. You don’t exist without a credit card in the USA.
  3. There is free Wi-Fi almost everywhere but for whatever deity you care to believe in’s sake, get yourself a $25 AT&T 500mb data plan so you are online all the time so you can find your fellow MVP’s or use online maps and stuff like that. Also, it’s great for keeping contact with the home front. AT&T first tests your phone if it works at all and even configures it before they charge you.
  4. Buses and light trail in Seattle are dirt cheap. Inside the city you pay about $2.25 for a trip from any given place to another and if you get back within a few hours, the return trip is free. The 550 bus from downtown to Bellevue costs $2.50. It partly runs inside the light rail tunnel, that’s why I couldn’t find it at first. There is also the 560 bus from SEA-TAC to Bellevue. Same price.
  5. Visit the Microsoft Store in the Bellevue mall. You won’t believe your eyes. Think hard before you take your credit card along ;-)
  6. Bring an umbrella. Seattle weather is erratic at best of times, but in February you can get everything from sunny weather to snow an back again in one day. People from the Netherlands or the UK just have to pretend they prepare for the weather at home ;-)

22 February 2012

Behavior to show a MessageBox from a ViewModel

Since I am a very lazy programmer and I not always want to register or define services and whatnot for showing a simple message I created this extremely simple behavior for showing a MessageBox from a ViewModel. I wrote the code for Windows Phone 7, but I suppose it could be used in Silverlight as well.

The behavior itself is as simple as this:

using System.Windows;
using System.Windows.Interactivity;

namespace Wp7nl.Behaviors
{
  public class MessageBoxDisplayBehavior : Behavior<FrameworkElement>
  {
    public const string MessagePropertyName = "Message";

    public string Message
    {
      get { return (string)GetValue(MessageProperty); }
      set { SetValue(MessageProperty, value); }
    }

    public static readonly DependencyProperty MessageProperty =
      DependencyProperty.Register(
        MessagePropertyName,
        typeof(string),
        typeof(MessageBoxDisplayBehavior),
        new PropertyMetadata(string.Empty, MessageChanged));

    public static void MessageChanged(DependencyObject d, 
      DependencyPropertyChangedEventArgs e)
    {
      var msg = e.NewValue as string;
      if (!string.IsNullOrEmpty(msg))
      {
        MessageBox.Show(msg);
      }
    }
  }
}

Easiest way to use it is to just drag it onto about any control in your Page using Blend, as long as it has the right data context, and select a string property to bind it to. In XAML, it usage looks something like this:

<Grid DataContext="{Binding ChooserViewModel}">
 <i:Interaction.Behaviors>
  <Wp7nl_Behaviors:MessageBoxDisplayBehavior 
    Message="{Binding MessageBoxMessage, Mode=TwoWay}"/>
 </i:Interaction.Behaviors>

Just one the one thing you might want to consider is how you define “MessageBoxMessage” in your ViewModel. I defined it as follows:

private string messageBoxMessage;
public string MessageBoxMessage
{
  get { return messageBoxMessage; }
  set
  {
    messageBoxMessage = value;
    RaisePropertyChanged(() => MessageBoxMessage);
  }
}
as opposed to what you would normally do, which is
private string messageBoxMessage;
public string MessageBoxMessage
{
  get { return messageBoxMessage; }
  set
  {
    if (messageBoxMessage != value)
    {
      messageBoxMessage = value;
      RaisePropertyChanged(() => MessageBoxMessage);
    }
  }
}
I intentionally left out the value check (in red), so RaisePropertyChanged always fires. This gives the real stupid mentally challenged users that make the same error multiple times multiple message boxes as well ;-)

06 February 2012

JSON deserialization with JSON.net: class hierarchies

In part 1 of this series I described the basics of creating classes from a JSON string and then simply deserializing the string into a (list of) classes. That way, you don’t have all the hooplah of SOAP, but still have strongly-typed classes in your client app. But beware, there is no formal contract either, so on a beautiful morning you might start to think that either you had too much of a drink yesterday evening, or that the company providing the data feed for your app indeed has started to sell Windows Phone 7 devices made by Sony, with a 65” screen.

Looking at the JSON string you now see something like this:

[
  {
    "Brand": "Nokia","Type" : "Lumia 800", "Device" : "Phone",
    "Specs":{"Storage" : "16GB", "Memory": "512MB","Screensize" : "3.7"}
  },
  {
    "Brand": "Sony", "Type" : "KDL-65HX920","Device" : "TV",
    "Specs":{"Screensize" : "65", "FullHD" : "Yes", "ThreeD" : "Yes" }
  },  
  { "Brand": "Nokia","Type" : "Lumia 900","Device" : "Phone",
    "Specs":{"Storage" : "8GB", "Memory": "512MB","Screensize" : "4.3" }
  },
  {
    "Brand": "Samsung", "Type" : "UE55C9000","Device" : "TV",
    "Specs":{"Screensize" : "55", "FullHD" : "Yes", "ThreeD" : "Yes" }
  },  
]
None of the two options mentioned before appear to be true: apparently the company has diversified. They are now selling TV's as well. Of course you could run this trough json2csharp, which will give you this:
public class Specs
{
    public string Storage { get; set; }
    public string Memory { get; set; }
    public string Screensize { get; set; }
    public string FullHD { get; set; }
    public string ThreeD { get; set; }
}

public class RootObject
{
    public string Brand { get; set; }
    public string Type { get; set; }
    public string Device { get; set; }
    public Specs Specs { get; set; }
}

This will work, but not for the purpose of what I’d like to show. We refactor the whole stuff into an object structure like this:

CodeScheme

Or, in code (put into a single file for the sake of brevity)

namespace JsonDemo
{
  public abstract class Device
  {
    public string Brand { get; set; }
    public string Type { get; set; }
  }
  
  public class Phone : Device
  {
    public PhoneSpecs Specs { get; set; }
  }
  
  public class Tv : Device
  {
    public TvSpecs Specs { get; set; }
  }
  
  public abstract class Specs
  {
    public string Screensize { get; set; }
  }
  
  public class PhoneSpecs : Specs
  {
    public string Storage { get; set; }
    public string Memory { get; set; }
  }
  
    public class TvSpecs: Specs
  {
    public string FullHd { get; set; }
    public string ThreeD { get; set; }
  }
}

If you think this is a ludicrous complicated way to store such a simple data structure I think you are quite right, but a) they don’t call me a Senior Software Architect for nothing, making things complicated is what I am told Architects do for a living, so I try to be a Good Boy ;-) and b) this is just for the purpose of the sample, so bear with me, right?

If you remember the crux of part 1: it all came down to one line of code, namely:

JsonConvert.DeserializeObject<List<Phone>>(r.EventArgs.Result);

This method actually has a second parameter: params Newtonsoft.Json.JsonConverter[] converters, which allows you to provide your own custom converters. Making those is pretty easy, and it becomes even more easy when you use the JsonCreationConverter<T> class that’s floating around the internet in various permutations. I nicked it from StackOverflow here.

using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace JsonDemo
{
  public abstract class JsonCreationConverter<T> : JsonConverter
  {
    protected abstract T Create(Type objectType, JObject jsonObject);

    public override bool CanConvert(Type objectType)
    {
      return typeof(T).IsAssignableFrom(objectType);
    }

    public override object ReadJson(JsonReader reader, Type objectType, 
      object existingValue, JsonSerializer serializer)
    {
      var jsonObject = JObject.Load(reader);
      var target = Create(objectType, jsonObject);
      serializer.Populate(jsonObject.CreateReader(), target);
      return target;
    }

    public override void WriteJson(JsonWriter writer, object value, 
   JsonSerializer serializer)
    {
      throw new NotImplementedException();
    }
  }
}

To make a converter, you subclass this object into a templated converter for the base class, override the “Create” method and off you go. Writing a converter for the Device/Phone/Tv hierarchy is pretty easy: you just have to check the value of the “Device” property, which you do like this:

using System;
using Newtonsoft.Json.Linq;

namespace JsonDemo
{
  public class JsonDeviceConverter : JsonCreationConverter<Device>
  {
    protected override Device Create(Type objectType, JObject jsonObject)
    {
      var typeName = jsonObject["Device"].ToString();
      switch(typeName)
      {
        case "TV":
          return new Tv();
        case "Phone":
          return new Phone();
        default: return null;
      }
    }
  }
}

For the Specs/PhoneSpecs/TvSpecs you do more or less the same, only now you have to check for the existence of certain properties, not the value. I decided that if an object has a “Storage” property it’s a PhoneSpecs, and if it has “FullHD” it’s a TVSpecs.

using System;
using Newtonsoft.Json.Linq;

namespace JsonDemo
{
  public class JsonSpecsConverter : JsonCreationConverter<Specs>
  {
    protected override Specs Create(Type objectType, JObject jsonObject)
    {
      if(jsonObject["Storage"] != null)
      {
        return new PhoneSpecs();
      }

      if (jsonObject["FullHD"] != null)
      {
        return new TvSpecs();
      }

      return null;
    }
  }
}

Finally, to get these converters being used by the deserializer you have to slightly modify the deserialization line:

var deserialized = JsonConvert.DeserializeObject<List<Device>>(r.EventArgs.Result, 
  new JsonDeviceConverter(), new JsonSpecsConverter());

And sure enough, if you put a breakpoint behind this line, you can place a watch on “deserialized” and see that the data structure has been deserialized in our artfully crafted class structure.

Deserialized

And that’s all there is to it. Demo solution with full code can be found here.

The third and final part of this series shows how to cache results and can be found here

01 February 2012

Behavior to force TextBox model update to prevent trouble with the ApplicationBar

A small quicky this time:

Problem:

  • TextBox, Text property bound to a string in my ViewModel
  • I type text in the TextBox
  • I click a “Save” button on my ApplicationBar
  • The string in my ViewModel is not updated. It never gets updated. WTF???

It appears the TextBox only updates it’s value to a bound string when it loses focus. And a TextBox does not lose focus when you click an ApplicationBar Button. Meh.

I have found a few solutions and workarounds, and in the end rolled my own:  a very small behavior that updates the binding every time you type something in your textbox. That’s a bit wasteful, but it works for me. It builds on the SafeBehavior pattern I wrote about earlier, and it’s so small I post it in one go:

using System.Windows.Controls;

namespace Wp7nl.Behaviors
{
  /// <summary>
  /// A behavior to for text box model update when text changes
  /// </summary>
  public class TextBoxChangeModelUpdateBehavior : SafeBehavior<TextBox>
  {
    protected override void OnSetup()
    {
      AssociatedObject.TextChanged += AssociatedObjectTextChanged;
    }

    protected override void OnCleanup()
    {
      AssociatedObject.TextChanged -= AssociatedObjectTextChanged;
    }

    void AssociatedObjectTextChanged(object sender, TextChangedEventArgs e)
    {
      var binding = AssociatedObject.GetBindingExpression(TextBox.TextProperty);
      if (binding != null)
      {
        binding.UpdateSource();
      }
    }
  }
}

I have read amongst other things Prism has a UpdateTextBindingOnPropertyChanged behavior. Well this one will be in the next version of my #wp7nl library on codeplex 

29 January 2012

Templating a XAML CheckBox to a thumbs-up/down control using Expression Blend

Preface
The checkbox has been been around in the Graphical User Interface for as long as I can remember doing GUI – since the early 90’s I guess. You know what, let’s make that “it’s been around for longer than I care to remember” ;). For my newest Windows Phone project I wanted something different. In stead of boring old 
checkbox 
 
I wanted something like this:
thumbsupdown
Turns out you can do this in pure XAML. And almost entirely in Expression Blend, too. I could just post the XAML and be done with it, but I like to document the track I took, not only to educate you, but also to remember myself how the hell I got here in the first place ;-).
Setting the stage
  • Open Visual Studio 2010
  • Create a new Windows Phone 7 (7.1 of course!) project,
  • Make a folder “icons”build actions
  • Download this image to your computer
  • Paste it in the “icons” folder in Visual Studio
  • Double check the image’s properties, they should be as showed to the right.
  • Save the project
Creating style and control template
  • Open the project in Expression blend
  • Put one (or more, for all I care) CheckBoxes on the phone page.
  • Select one of them, then click in the main Blend menu “Object/Edit Style/Create Empty”.
  • In the dialog that follows, enter “Thumbupdowncheckboxstyle” for a name and select “Application” under “Define in”
  • You will get a screen with a single CheckBox. Right click it, select “Edit template/Create Empty”.
  • In the dialog that follows, enter “Thumbupdowncheckboxtemplate” for a name and select “Application” under “Define in”
First thing you will notice is that the selected CheckBox completely disappears from your design surface. That’s because basically you have replaced the entire look for the CheckBox by an empty template, which is essentially well, pretty empty indeed. It only contains a grid, and even that’s gonna go.
  • Delete the Grid
  • Add a Rectangle to the template by double clicking on the Rectangle button from the Assets toolbar on the left
This is a good moment to turn on Split View in the designer, because that shows you what the designer is actually doing. Right-click the rectangle in the Objects and Timeline panel, and select “View XAML”. At this point you will see only this:
<Application.Resources>

  <ControlTemplate x:Key="Thumbupdowncheckboxtemplate" TargetType="CheckBox">
    <Rectangle Fill="#FFF4F4F5" Stroke="Black"/>
  </ControlTemplate>

  <Style x:Key="Thumbupdowncheckboxstyle" TargetType="CheckBox">
    <Setter Property="Template" Value="{StaticResource Thumbupdowncheckboxtemplate}"/>
  </Style>

</Application.Resources>
And the design surface will only show a horizontal white rectangle with a black border.
Default control size
ResourcesFirst and foremost, set the default size of your control. To get this done, look right top, select the Resources tab and expand App.Xaml. Then proceed as follows:
  • Right-click Thumbupdowncheckboxstyle
  • Select “Edit”
  • Select the “Properties” tab left of the “Resources” tab
  • Locate the “Width” and “Height” fields and enter 40 for both.
Your XAML now should look like this:
<Application.Resources>

  <ControlTemplate x:Key="Thumbupdowncheckboxtemplate" TargetType="CheckBox">
    <Rectangle Fill="#FFF4F4F5" Stroke="Black"/>
  </ControlTemplate>

  <Style x:Key="Thumbupdowncheckboxstyle" TargetType="CheckBox">
    <Setter Property="Template" Value="{StaticResource Thumbupdowncheckboxtemplate}"/>
    <Setter Property="Width" Value="40"/>
    <Setter Property="Height" Value="40"/>
  </Style>

</Application.Resources>
Propagate default size to template
Now go back to editing the Control template again:
  • Once again go to the “Resources” tab left top
  • Right-click Thumbupdowncheckboxtemplate
  • Select “Edit”.
  • Select the Rectangle and Click the tab “Properties” top left againwidth
  • Click the little square all the way to the right behind the field “Width”
  • This will popup a menu. Select “Template Binding/Width”
  • Click the little square behind “Height” and Select “Template Binding/Height”
This will set the width and height of the rectangle to the full width and height of the control. If the user does not set a specific width and height, the values in the default Setters (both 40) will be used. XAML at this point:
<Application.Resources>

  <ControlTemplate x:Key="Thumbupdowncheckboxtemplate" TargetType="CheckBox">
    <Rectangle Fill="#FFF4F4F5" Stroke="Black" Width="{TemplateBinding Width}" 
    Height="{TemplateBinding Height}"/>
  </ControlTemplate>

  <Style x:Key="Thumbupdowncheckboxstyle" TargetType="CheckBox">
    <Setter Property="Template" Value="{StaticResource Thumbupdowncheckboxtemplate}"/>
    <Setter Property="Width" Value="40"/>
    <Setter Property="Height" Value="40"/>
  </Style>

</Application.Resources>
Initial colors
Next steps:
  • ColorClick the white white rectangle behind “Fill”
  • Don’t bother to select a color: simply type in “Green” in the text box and Blend will make a pretty hex string of it ;-)
  • After that, click the little white square behind “Stroke”
  • From the popup-menu, select “Reset”
The design surface now shows a green rectangle. Oh wow ;-) but bear with me, we will get there in the end. Your XAML should now look like this:
<Application.Resources>

  <ControlTemplate x:Key="Thumbupdowncheckboxtemplate" TargetType="CheckBox">
    <Rectangle Fill="Green" Width="{TemplateBinding Width}" Height="{TemplateBinding Height}"/>
  </ControlTemplate>

  <Style x:Key="Thumbupdowncheckboxstyle" TargetType="CheckBox">
    <Setter Property="Template" Value="{StaticResource Thumbupdowncheckboxtemplate}"/>
    <Setter Property="Width" Value="40"/>
    <Setter Property="Height" Value="40"/>
  </Style>

</Application.Resources>
Including the image as an ‘opacity mask’
OpacityBlend’s greatest asset – it’s enormous capabilities – unfortunately is also sometimes its Achilles’ heel: there’s a bewildering set of options that’s not always easy to find your way in. Fortunately, at the top of the Properties there’s a Search box that helps you find that hard-to-find-options. Which is extremely helpful – if you happen to know what to look for ;-). In this case:
  • Enter “Opacity” in the Search box
  • Click “No Brush”
  • Select “Tile Brush” – that’s the 2nd icon from the left
  • That produces a drop-down where you can select “icons/thumbsup.png”
your XAML should now look like this:
<Application.Resources>

  <ControlTemplate x:Key="Thumbupdowncheckboxtemplate" TargetType="CheckBox">
  <Rectangle Fill="Green" Width="{TemplateBinding Width}" Height="{TemplateBinding Height}">
    <Rectangle.OpacityMask>
    <ImageBrush Stretch="Fill" ImageSource="icons/thumbsup.png"/>
    </Rectangle.OpacityMask>
  </Rectangle>
  </ControlTemplate>

  <Style x:Key="Thumbupdowncheckboxstyle" TargetType="CheckBox">
  <Setter Property="Template" Value="{StaticResource Thumbupdowncheckboxtemplate}"/>
  <Setter Property="Width" Value="40"/>
  <Setter Property="Height" Value="40"/>
  </Style>

</Application.Resources>
desing2designYour design surface should now looks like to the image to the left, which is kinda crummy. You can use the little triangle on the right bottom, and the two little lines on the right and the bottom, to resize the design surface. This will have no effect on the control template itself, it will make just make it look better (see right image) .
You can also manually add the attributes d:DesignWidth="75" and d:DesignHeight="75" to the Rectangle.
Defining Visual States
statesA CheckBox has certain states, the most obvious being Checked and Unchecked. Actually there are quite a lot more, and you can see them by clicking on the “States”  tab. Now all these states are defined, but there are no visuals connected to it anymore, since you have replaced the control template by something empty and started filling in yourself. This next step will bring a bit of those visual states back. To prepare for that:
  • Make sure the Rectangle is selected in the “Objects and Timeline”  panel left
  • In the Properties panel to the right of the screen, scroll down to “Transform”
  • Expand the Transform panel if it’s collapsed
  • Selected the leftmost tab
  • Enter 0.5 in both X and Y boxes
transformXAML at this point:
<Application.Resources>

  <ControlTemplate x:Key="Thumbupdowncheckboxtemplate" TargetType="CheckBox">
    <Rectangle Fill="Green" Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" 
       d:DesignWidth="75" d:DesignHeight="75" RenderTransformOrigin="0.5,0.5">
      <Rectangle.RenderTransform>
        <CompositeTransform TranslateX="0.5" TranslateY="0.5"/>
      </Rectangle.RenderTransform>
      <Rectangle.OpacityMask>
        <ImageBrush Stretch="Fill" ImageSource="icons/thumbsup.png"/>
      </Rectangle.OpacityMask>
    </Rectangle>
  </ControlTemplate>

  <Style x:Key="Thumbupdowncheckboxstyle" TargetType="CheckBox">
    <Setter Property="Template" Value="{StaticResource Thumbupdowncheckboxtemplate}"/>
    <Setter Property="Width" Value="40"/>
    <Setter Property="Height" Value="40"/>
  </Style>

</Application.Resources>
In the “States”  panel, click on the “Checked” state. This will add quite some XAML code: you will see a “VisualStateManager.VisualStateGroups” tag appear, defining all three states of the “CheckStates”  group, i.e. “Checked”, “Unchecked”  and “Indeterminate”.
  • Now Select the “Unchecked”  state
  • Make sure the “Rectangle” still is selected in the “Objects and Timeline”  panel
  • Select the “Properties” tab on the top right again
  • Select the (now green) “Fill” Rectangle again.
  • In the box where you previously typed “Green” (which will say ”#FF008000” now), type “Red”. The thumbs-up image will now turn red
  • flipScroll down to “Transform” again
  • Select the right most tab
  • Select the “Flip Y-axis” button, in the middle. The thumbs-up image will now flip vertically and turn into a thumbs-down picture.
  • recordingLocate the little red button on top of the design pane that says “Unchecked state recording is on”. Click it and the text should change into “Unchecked state recording is off”.
If you press F5, the project will compile and run (yes, that works from Blend as well), and you will see that the checkbox shows a green thumbs-up image when selected, and a red thumbs-down image when unselected.
Now, for a finale to make things a little more visually appealing:
  • AnimateGo back to the “States” tab again
  • Select the Textbox with “0 s” in the “Default transition” panel above state “Unchecked”
  • Type 0.5 in the text box
  • And press F5 again.
You will now see the thumbs not simply flip: now it rotates in half a second and change color from red via orange to green. By simply specifying a time you tell the application to actually infer an animation. And there you are. A completely customized, animated, thumb-up-thumbs-down control with just some clicking around. Code-wise it behaves just like a normal checkbox. And if you want to make more of these checkboxes, just select a standard CheckBox, right click it, Select “Edit template/Apply Resources/Thumbupdowncheckboxstyle” and boom – yet another Thumbup-thumbsdown control.
Final XAML:
<Application.Resources>

  <ControlTemplate x:Key="Thumbupdowncheckboxtemplate" TargetType="CheckBox">
    <Rectangle x:Name="rectangle" Fill="Green" Width="{TemplateBinding Width}" 
               Height="{TemplateBinding Height}" 
               d:DesignWidth="75" d:DesignHeight="75" RenderTransformOrigin="0.5,0.5">
      <Rectangle.RenderTransform>
        <CompositeTransform TranslateX="0.5" TranslateY="0.5"/>
      </Rectangle.RenderTransform>
      <Rectangle.OpacityMask>
        <ImageBrush Stretch="Fill" ImageSource="icons/thumbsup.png"/>
      </Rectangle.OpacityMask>
      <VisualStateManager.VisualStateGroups>
        <VisualStateGroup x:Name="CheckStates">
          <VisualStateGroup.Transitions>
            <VisualTransition GeneratedDuration="0:0:0.5"/>
          </VisualStateGroup.Transitions>
          <VisualState x:Name="Indeterminate"/>
          <VisualState x:Name="Unchecked">
            <Storyboard>
              <DoubleAnimation Duration="0" To="-1" 
                    Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleY)" 
                    Storyboard.TargetName="rectangle" d:IsOptimized="True"/>
              <ColorAnimation Duration="0" To="Red" 
                   Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" 
                   Storyboard.TargetName="rectangle" d:IsOptimized="True"/>
            </Storyboard>
          </VisualState>
          <VisualState x:Name="Checked"/>
        </VisualStateGroup>
      </VisualStateManager.VisualStateGroups>
    </Rectangle>
  </ControlTemplate>

  <Style x:Key="Thumbupdowncheckboxstyle" TargetType="CheckBox">
    <Setter Property="Template" Value="{StaticResource Thumbupdowncheckboxtemplate}"/>
    <Setter Property="Width" Value="40"/>
    <Setter Property="Height" Value="40"/>
  </Style>
</Application.Resources>
You could of course go on and define all other states, but this already works pretty well IMHO ;-). Oh and by the way: this should work on any XAML platform, not just on Windows Phone. And for those who don’t like typing or copy-and-pasting, here is, as always, the complete demo solution.
Thanks to Willem Meints for helping me out via twitter on default setters for styles.

22 January 2012

JSON deserialization with JSON.net: basics

I’ve been contemplating an article about handling JSON for some time now, but it turned out to be a rather long article. So I’d thought to try something new, and write a short series in three parts.

  • Part 1 handles the basics
  • Part 2 handles advanced deserialization with class hierarchies
  • Part 3 handles a caching-and-updating scenarios.

And this is part 1 ;-)

This whole article actually boils down to one line of code, but I need to go trough some hooplah to show you how to use it. It all begins with the data. Consider this piece of quite readable JSON, describing a few recent Windows Phone models.

[
  {
    "Brand": "Nokia","Type" : "Lumia 800",
    "Specs":{"Storage" : "16GB", "Memory": "512MB","Screensize" : "3.7"}
  },
  {
    "Brand": "Nokia", "Type" : "Lumia 710",
    "Specs":{"Storage" : "8GB","Memory": "512MB","Screensize" : "3.7"}
  },  
  { "Brand": "Nokia","Type" : "Lumia 900",
    "Specs":{"Storage" : "8GB", "Memory": "512MB","Screensize" : "4.3" }
  },
  { "Brand": "HTC ","Type" : "Titan II",
    "Specs":{"Storage" : "16GB", "Memory": "512MB","Screensize" : "4.7" }
  },
  { "Brand": "HTC ","Type" : "Radar",
    "Specs":{"Storage" : "8GB", "Memory": "512MB","Screensize" : "3.8" }
  }
]

JSON is rather compact, which is a great feature when you are developing for mobile devices. It has also a few downsides as far as client programming is concerned:

  • generating client code for it that does all the parsing and calling, as for SOAP, is not a standard feature of Visual Studio,
  • it’s almost impossible to read for an ordinary human being,
  • deciphering it into classes is a lot of work,
  • hand coding a parser for it is not fun.

Which is why you don’t. There are several ways of generating classes from JSON, the simplest way is this website: json2csharp by Jonathan Keith. You copy a JSON result into the upper textbox, hit the “Generate” button and out come your classes:Json2Csharp

There are more sites that do the same, by the way, but this is what I use. Next steps:

  • Fire up Visual Studio
  • Create a new Windows Phone project (for instance JsonDemo)
  • Plonk the classes generated above in the project. Bonus cookies if you split them in separate files and add namespaces to them. Bonus donut if you, like me, think “RootObject” is actually a pretty ugly name for an object - so change it to "Phone".
  • Click Tools/Library Package Manager/Manage NuGet Packages for Solution (you do have the NuGet Package Manager installed, don’t you? If not, stop whatever you are doing now and get it right this instance, you hear me ;)? )
  • Search for JSON.Net
  • Click install. This will add a reference to NewtonSoft.Json.dll to your product.
  • Add references to Microsoft.Phone.Reactive and System.Observable because they are going to be needed in the next step.

To make the result visible, add some XAML to the default content panel in Mainpage.Xaml – just a button and a templated ListBox, no rocket science here:

<StackPanel>
  <Button Name="Load"
      VerticalAlignment="Top"
      Content="Load phones" Click="Load_Click" />
  <ListBox x:Name="PhoneList" Height="532">
    <ListBox.ItemTemplate>
      <DataTemplate>
        <StackPanel Orientation="Horizontal">
          <TextBlock Text="{Binding Brand}" 
                 Margin="0,0,12,0" />
          <TextBlock Text="{Binding Type}"/>
        </StackPanel>
      </DataTemplate>
    </ListBox.ItemTemplate>
  </ListBox>
</StackPanel>

Finally, open MainPage.Xaml.cs and add the method Load_Click as displayed below.

using System;
using System.Collections.Generic;
using System.Net;
using System.Windows;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Reactive;
using Newtonsoft.Json;

namespace JsonDemo
{
  public partial class MainPage : PhoneApplicationPage
  {
    // Constructor
    public MainPage()
    {
      InitializeComponent();
    }

    private void Load_Click(object sender, RoutedEventArgs e)
    {
      var w = new WebClient();
      Observable
        .FromEvent<DownloadStringCompletedEventArgs>(w, "DownloadStringCompleted")
        .Subscribe(r =>
        {
          var deserialized = 
            JsonConvert.DeserializeObject<List<Phone>>(r.EventArgs.Result);
          PhoneList.ItemsSource = deserialized;
        });
      w.DownloadStringAsync(
        new Uri("http://www.schaikweb.net/dotnetbyexample/JSONPhones1.txt"));
    }
  }
}

JsonSerializerAnd there it is, the one line of code that this is all about. Call the DeserializeObject method, template it with the return type you want, and stuff the JSON string in it. Result: a list of objects with their properties filled, even if there are things like nested objects (specs in these case) and arrays in there.

If you run the demo solution you get the result displayed in the image on the right. Keep in mind this code is by no means Windows Phone specific. There are JSON.Net implementations for virtually all frameworks available. So should you feel the need to use this from Silverlight or full .NET: it’s there.

You should, by the way, pay attention to the structure of the JSON. The code I show works for a list. A list in JSON starts with a square bracket: [. If your JSON starts with a curly brace: { then you get returned a single object - a so called root object. In that case, your deserialization should code return a single object in stead of a list as well, i.e. something like

var deserialized = 
     JsonConvert.DeserializeObject<Phone>(r.EventArgs.Result);

Finally, a ninja tip:

  • Click Tools/Library Package Manager/Manage NuGet Packages for Solution  again
  • Search for SharpGIS.GZipWebClient
  • Click install
  • Change “WebClient” in the Load_Click method to SharpGIS.GZipWebClient

This plug-in replacement for WebClient by Morten Nielsen adds support for GZIP compressed web requests – this reduces network traffic even further, apparently boosting load performance significantly. You won’t really notice the difference on such a small data files as used in this sample, but as your JSON return values get larger, so will be the impact of using this library.

For the record: I am not ill nor do I have forsaken MVVM, but I tried to make the example as simple as possible so yes, I used a little code behind, as to not to cloud the solution in architectural frills. ;-)

Thanks to Matthijs Hoekstra for putting me on track to this, and to fellow #wp7nl developer Leon Zandman for correcting some annoying typos.