Corrado's Blog 2.0

Online thoughts of a technology funatic

XAML relative binding trick

MVVM newcomers find creating a UI like this (a simple ListView containing a button that removes current row) quite intricated.

image

This because, while you can add a command to the item bound to each row, it’s more convenient to have a common DeleteCommand on parent ViewModel that accepts the Item to remove from the collection feeding the list.

Here’s our ViewModel:

public class MyViewModel { private RelayCommand<ReportUnit> deleteCommand; public MyViewModel() { this.Items = new ObservableCollection<ReportUnit>(); for (int i = 0; i < 10; i++) { this.Items.Add(new ReportUnit() { Name = $"Item {i}" }); } } public RelayCommand<ReportUnit> DeleteCommand { get { return this.deleteCommand ?? (this.deleteCommand = new RelayCommand<ReportUnit>((o) => { this.Items.Remove(o); })); } } public ObservableCollection<ReportUnit> Items { get; private set; } } public class ReportUnit { public string Name { get; set; } }

And here’s the page XAML:

<Page x:Class="DemoBinding.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <Page.Resources> <Style x:Key="ListItemContainerStyle" TargetType="ListViewItem"> <Setter Property="HorizontalContentAlignment" Value="Stretch" /> </Style> </Page.Resources> <Grid x:Name="RootGrid"> <ListView ItemsSource="{Binding Items}" ItemTemplate="{StaticResource MyItemTemplate}" ItemContainerStyle="{StaticResource ListItemContainerStyle}"> </ListView> </Grid> </Page>

The “magic” is of course inside MyItemTemplate:

<DataTemplate x:Key="MyItemTemplate"> <Grid d:DesignWidth="568.775" Height="80" d:DesignHeight="100"> <Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> <ColumnDefinition Width="100" /> </Grid.ColumnDefinitions> <TextBlock TextWrapping="Wrap" Text="{Binding Name}" VerticalAlignment="Center" FontSize="26.667" /> <Button Grid.Column="1" Content="Delete" HorizontalAlignment="Stretch" Command="{Binding DataContext.DeleteCommand, ElementName=RootGrid}" CommandParameter="{Binding}" VerticalAlignment="Stretch" Margin="5" /> </Grid> </DataTemplate>

As you see, the  button ‘steal’ the DataContext of RootGrid element and invokes MyViewModel’s DeleteCommand while passing its own DataContext as CommandParameter.

Simple and clean. Smile

Dynamic localization of Windows Store apps

Localizing a Windows Store app is a fairly easy task thanks to the x:UId attribute introduced with WinRT.
If you need to create a Multilanguage application just add to your Visual Studio solution a folder named Strings and below it add a folder for each language you want to support using the two letter ISO language as name.
In this picture I have a solution that support Italian and American English

image

Inside each folder I’ve added a resource file and note that there’s a Resource.resw file just below Strings folder, it represent the default fallback resource language file that will be used in case your app will be executed on a system whose language is different than America English or Italian.

Inside each Resource.resw add the property of the control to localize, in our case we want to localize the Text property of a TextBlock, so the file content for each will be:

en-US folder

image

it-IT folder

image

Now to localize the Text property of our TextBlock all we need to to is use this XAML:

1 <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> 2 <TextBlock x:Uid="WelcomeMessage" 3 VerticalAlignment="Center" 4 Foreground="BlueViolet" 5 Text="..." 6 HorizontalAlignment="Center" 7 FontSize="48" /> 8 </Grid>

Here’s what you’ll see when the code is executed on an Italian pc:

image

Very easy isn’t it? Smile

This approach let you do more than just localize Text, if you want to dig more into it you can read this article

Ok, but imagine you have this mandatory requests:

  • 1-Application language can be unrelated to machine language (French app running on an Italian machine)

2-Language switching should not require an application reboot

3-You must use a MVVM friendly solution

Ok, things can get a little more intricate here  and since I haven’t found a standard solution I solved this way:

Step 1: Since we’ll deal with text only let’s rename resources inside .resw files from WelcomeMessage.Text to just WelcomeMessage (see below)

image

Step 2: Let’s create a ViewModel (yes, MVVM always requires a ViewModel…) and let’s add the necessary code to load the strings dynamically:

1 public class MyViewModel : INotifyPropertyChanged 2 { 3 private ResourceContext resoureContext; 4 5 public MyViewModel(string language) 6 { 7 this.UpdateCulture(language); 8 } 9 10 public void UpdateCulture(string language) 11 { 12 this.resoureContext = ResourceContext.GetForCurrentView(); 13 this.resoureContext.Languages = new List<string> { language }; 14 } 15 16 public string GetResource(string stringResource) 17 { 18 try 19 { 20 var resourceStringMap = ResourceManager.Current.MainResourceMap.GetSubtree("Resources"); 21 return resourceStringMap.GetValue(stringResource, this.resoureContext).ValueAsString; 22 } 23 catch (Exception ex) 24 { 25 return $"?{stringResource}?"; 26 } 27 } 28 29 ... 30 }

The magic here is inside UpdateCulture and GetResource methods, if we name the TextBlock in previous XAML snippet MyTextBlock we can dynamically change its text using this code:

1 public sealed partial class MainPage : Page 2 { 3 public MainPage() 4 { 5 this.InitializeComponent(); 6 this.MyTextBlock.Text = new MyViewModel("it-IT").GetResource("WelcomeMessage"); 7 8 } 9 }

But since we’re using MVVM we want to use databinding for that instead of code and we need a smart solution otherwise localization can become tedious, solution is not very far: just use an indexer:

Just add this line of code to the ViewModel

1 public string this[string key] => this.ApplicationController.GetResource(key);

And let’s inform binding that our indexer property need to be refreshed so that all texts will be reloaded when user changes the UI language at runtime modifying the UpdateCulture method this way:

1 public void UpdateCulture(string language) 2 { 3 this.resoureContext = ResourceContext.GetForCurrentView(); 4 this.resoureContext.Languages = new List<string> { language }; 5 this.OnPropertyChanged("Item[]"); 6 }

Note the trick of using “Item[]” as property name to signal that the class indexer has changed.

So let’s bind TextBlock’s Text property to viewmodel indexer using this syntax, and you’re done.

1 <TextBlock x:Name="MyTextBlock" 2 VerticalAlignment="Center" 3 Foreground="BlueViolet" 4 Text="{Binding [WelcomeMessage]}" 5 HorizontalAlignment="Center" 6 FontSize="48" />

You can find a complete example here.

Have fun!

Introducing Xamarin Forms Behaviors

The goal of this post is to introduce you to the Xamarin.Forms.Behavior package available on NuGet, if you landed here I presume you already know what Xamarin Forms is, if not, follow this link so you’ll understand why so many developers are excited about it.

Now that I can assume you’re a Xamarin Forms master, let’s concentrate on Behaviors. Once I read Xamarin Forms documentation I was really happy to see that you can design cross-platforms user interfaces using XAML and that the XAML support in Xamarin Forms is nearly identical to the one available in Windows development apart some minor differences.

If you don’t know what a Behavior is I can summarize it for you in this sentence: The capabity to add code inside a UI described using XAML” the question now is: Why should I add code inside XAML, hasn’t code behind created just for this? well, yes and no, if you know MVVM (if not, you should!) you’ll know that the entire logic should reside inside the VieModel associated with the View and that communication between View and ViewModel should happen (in a perfect world) through Databinding.

Unfortunately in “real” world this is not always possible and you have to use code to make things work, often this code resides in code behind and for this reason is not testable and not even reusable.

Let’s take an example: A simple view made up of two Entry elements and a Button, the View has a ViewModel associated to its BindingContext and we want the button to be enabled only when both Entry fields are not empty and it’s enabled state must toggle “live” while user typing.

This is the XAML contained inside Xamarin Forms’s PCL project:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"      
        x:Class="Xamarin.Behaviors.Demo.Views.MainView">
 <StackLayout>
  <Entry Placeholder="Enter Firstname" />
  <Entry  Placeholder="Enter Lastname" />
  <Button Text="Ok" Command="{Binding TestCommand}" />    
 </StackLayout>
</ContentPage>

and here’s the ViewModel:

public class MainViewModel : INotifyPropertyChanged
 {
  public event PropertyChangedEventHandler PropertyChanged;

  private string firstName = "Nome";
  private string lastName = "Cognome";
  private Command testCommand;
  private Command<object> unfocusedCommand;
  private string message;
  private string welcomeMessage; 
  
  public string FirstName
  {
   get { return this.firstName; }

   set
   {
    if (value != this.firstName)
    {
     this.firstName = value;
     this.RaisePropertyChanged();
     this.TestCommand.ChangeCanExecute();
    }
   }
  }
  
  public string LastName
  {
   get { return this.lastName; }

   set
   {
    if (value != this.lastName)
    {
     this.lastName = value;
     this.RaisePropertyChanged();
     this.TestCommand.ChangeCanExecute();
    }
   }
  }
  
  public string Message
  {
   get  {return this.message; }

   private set
   {
    if (value != this.message)
    {
     this.message = value;
     this.RaisePropertyChanged();
    }
   }
  }  
  public string WelcomeMessage
  {
   get { return this.welcomeMessage;}

   set
   {
    if (value != this.welcomeMessage)
    {
     this.welcomeMessage = value;
     this.RaisePropertyChanged();
    }
   }
  }
  
  public Command TestCommand
  {
   get
   {
    return this.testCommand ?? (this.testCommand = new Command(
      () =>
      {
       this.WelcomeMessage = string.Format("Hello {0} {1}", this.FirstName, this.LastName);
      },
      () =>
      {
       return !string.IsNullOrEmpty(this.FirstName) && !string.IsNullOrEmpty(this.LastName);
      }));
   }
  }

  public Command<object> UnfocusedCommand
  {
   get
   {
    return this.unfocusedCommand ?? (this.unfocusedCommand = new Command<object>(
      (param) =>
      {
       this.Message = string.Format("Unfocused raised with param {0}", param);
      },
      (param) =>
      {
       // CanExecute delegate
       return true;
      }));
   }
  }
  
  protected virtual void RaisePropertyChanged([CallerMemberName] string propertyName = null)
  {
   PropertyChangedEventHandler handler = PropertyChanged;
   if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
  }
 }

ViewModel is associated with the View’s constructor for brevity:

public partial class MainView
 {
  public MainView()
  {
   InitializeComponent();
   this.BindingContext = new MainViewModel();
  }
 }

As you see the Button is connected to ViewModel’s TestCommand via Databinding and thanks to ICommand interface it is enabled only when both ViewModel’s FirstName and LastName properties are not empty.

Now the hardest part: How do we update those properties when Entry content changes?

Easy: we subscribe Entry’s TextChanged method and when it fires we update associated property. Cool, but wouldn’t it be nice if we could encapsulate this logic into a reusable component, usable in XAML, so that we don’t need to reinvent the wheel each time?

Here’s where Behaviors can help you.

Install Xamarin.Forms.Behaviors Package from NuGet and  and create a class that inherits from Behavior<T> where <T> is the UI component that the behavior will attach to, in our case the Entry element.

public class TextChangedBehavior : Behavior<Entry>
 {
  public static readonly BindableProperty TextProperty = BindableProperty.Create<TextChangedBehavior, string>(p => p.Text, null, propertyChanged: OnTextChanged);

  private static void OnTextChanged(BindableObject bindable, string oldvalue, string newvalue)
  {
   (bindable as TextChangedBehavior).AssociatedObject.Text = newvalue;
  }

  public string Text
  {
   get { return (string)GetValue(TextProperty); }
   set { SetValue(TextProperty, value); }
  }

  protected override void OnAttach()
  {
   this.AssociatedObject.TextChanged += this.OnTextChanged;
  }

  private void OnTextChanged(object sender, TextChangedEventArgs e)
  {
   this.Text = e.NewTextValue;
  }

  protected override void OnDetach()
  {
   this.AssociatedObject.TextChanged -= this.OnTextChanged;
  }
 }

Behavior and Behavior<T> both have OnAttach and OnDetach methods that gets invoked when the behavior is attached/detached from parent UI element, so we subscribe TextChanged event and when it triggers we update behavior’s bindable property Text.

I’ll be you’re now wondering: How do I use it in my XAML? very easy, here’s the updated XAML for Entry element (just first one indicated for brevity)

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
        xmlns:b="clr-namespace:Xamarin.Behaviors;assembly=Xamarin.Behaviors"
        x:Class="Xamarin.Behaviors.Demo.Views.MainView">
 <StackLayout>
  <Entry Placeholder="Enter Firstname" >
   <b:Interaction.Behaviors>
    <b:BehaviorCollection>
     <b:TextChangedBehavior Text="{Binding FirstName, Mode=TwoWay}" />     
    </b:BehaviorCollection>
   </b:Interaction.Behaviors>
  </Entry>
  ...
  </StackLayout>
</ContentPage
  

After adding a xmlns pointing to Xamarin.Forms.Behavior namespace we “inject” the code into XAML, so now as we type on Entry the Firstname property it’s updated (and vice versa of course thanks to INotifyPropertyChanged and Two Way binding mode.)

One of the real advantages of using Behaviors in Windows Development is that they’re visually supported by Expression Blend design tool, so you don’t even need to write any XAML, just drag the behavior and configure it using point and click Smile unfortunately since we don’t even have a XAML designer in Xamarin Forms typing is the only available solution at the moment.

If you think the syntax is quite boring I agree, that’s why inside the project on GitHub I added a XML snippet that generates the surrounding code for you, just grab it and import it in Visual Studio, add the behavior syntax and press Ctrl+K+S

image

and you’ll have the plumbing code added for you, don’t forget to add required xmlns directive/s.

xmlns:b="clr-namespace:Xamarin.Behaviors;assembly=Xamarin.Behaviors"

since it’s not added automatically by the snippet.

Am not a Xamarin Studio expert so I don’t know if it support XML Expansions, if so send me the snippet and I’ll add it to the project.

Here’s the XAML taken from the example available on GitHub:

<Entry Placeholder="Enter Firstname" >
   <b:Interaction.Behaviors>
    <b:BehaviorCollection>
     <b:TextChangedBehavior Text="{Binding FirstName, Mode=TwoWay}" />
     <b:EventToCommand EventName="Unfocused" Command="{Binding UnfocusedCommand}" CommandParameter="FirstName" />
    </b:BehaviorCollection>
   </b:Interaction.Behaviors>
  </Entry>

the example shows two behaviors included in the package, TextChangedBehavior and EventToCommand, a behavior that invokes a Command when an event occurs.

Congratulations! you’re now able to write your own behavior, group them in a portable library and reuse it in every Xamarin Forms project.

If you’re already a XAML developer you already know what behaviors are and I hope you’ll like to have them in Xamarin Forms, if not I encourage you to play with it, personally can’t even think using XAML with MVVM without them.

Ok, now let’s dream about a Xamarin Forms designer supporting the same Behavior infrastructure as Expression Blend, am I asking too much? we’ll see.

Cheers!

NuGet Package: here

GitHub repo: here

MvvmStack for WinJS: Application Resuming support

I’ve checked in a new version of MvvmStack that has a small tweak and a “new” feature, let’s start with the latter:

Resuming support

Sometimes you need to be informed when app resumes, an example is because you want to download some fresh data if app has been suspended longer than a certain amount of time.

With MvvmStack all you need to do to is to add a onAppResuming method to your services and/or ViewModels, something like: (see sectionViewModel.js on sample code)

onAppResuming: function () {
            console.log("SectionViewModel notified that app has been resumed.")
        }

And it will be invoked each time app resumes.

The ‘tweak’ regards the way you add new  ViewModels, in this post, on Closing section i mention:

“3- Add a new property “pagenameViewModel” to ViewModelLocator’s  viewModels object“ 

starting from this version the step is no longer required Smile

MvvmStack for WinJS: Command support

A Command represents an abstraction over an action, the command can also indicate whether the action is available or not and, normally, UI elements tied to a command disables themselves when command is not available, if you’re new to MVVM’s commanding I recommend this article.

While more a .NET concept than a Mvvm pattern core feature, i decided to add support for it with latest checkin since its wide popularity and to keep the stack aligned with other .NET based libraries.

In  .NET a Command depends upon the ICommand interface and it is generally implemented by generic classes like RelayCommand or DelegateCommand, for MvvmStack I’ve used a simpler implementation available in relayCommand.js

(function (winjs) {
    "use strict";

    var RelayCommand = WinJS.Class.define(function(execute) {
        this.execute = execute;
        this.execute.supportedForProcessing = true;
        this.canExecute = winjs.Binding.as({value:true});
    },
        {
            execute: null,
            canExecute: null
        });

    winjs.Namespace.define("MvvmStack", {
        RelayCommand: RelayCommand
    });

})(WinJS)

To use it all you need is to expose instances of RelayCommand from your viewmodels, sample code exposes them in sectionViewModel.js

firstCommand: new mvvmStack.RelayCommand(function (element) {
            this.currentPage.value = 0;
            this.firstCommand.canExecute.value = false;
            this.lastCommand.canExecute.value = true;
        }),
        lastCommand: new mvvmStack.RelayCommand(function (element) {
            this.currentPage.value = this.images.length - 1;
            this.firstCommand.canExecute.value = true;
            this.lastCommand.canExecute.value = false;
        }),

then we wire the commands with application bar commands in section.html page

<div data-win-control="WinJS.UI.AppBar">
            <button
                data-win-control="WinJS.UI.AppBarCommand"
                data-win-bind="onclick:firstCommand Binding.Mode.command"
                data-win-options="{icon:'home', id:'', label:'Home', section:'global', type:'button'}">
            </button>
            <button
                data-win-control="WinJS.UI.AppBarCommand"
                data-win-bind="onclick:lastCommand Binding.Mode.command"
                data-win-options="{icon:'next', id:'', label:'Last', section:'global', type:'button'}">
            </button>
        </div>

In order to keep button state in sync with commands availability we use a new Binding.Mode.command initializer, also note how click event binds to command and not to its execute function.

As usual the binding initializer is defined inside binding-extensions.js, you can update it in case you need to handle other enable/disable scenarios.

Binding.Mode.command automatically adds a mvvm-disabled class to invoking element (app bar buttons in our case) so that you can use a css class to change the look of the control while in disabled state.

To see commands in action, run the sample, navigate to section page and click application bar’s buttons or navigate through images to see how buttons follow current’s image position.

Hope you like it Smile

PS: In order to simplify dev life I’ve added a watch function to viewModelBase that allows to invoke a function when an observable property changes (just a simple wrapper around bind function indeed Winking smile)

MvvmStack for WinJS: Services persistence

While refactoring MvvmStack for WinJS code i noticed that I did not show how to persist the state of the services when the app get suspended, so i checked in a new version that persist the data contained inside imageService.js (in a real world app, the data will probably come from a remote server).

The strategy I use is to let the services that need to keep their state add themselves to a services collection exposed by applicationControllerBase object that is passed to each service instance:

(function (winjs, applicationController) {
    var images = [];
    var cachedId;
    var imageService = {
        load: function (id) {
            return new winjs.Promise(function (c, e) {
                //Returns cached images when available
                if (cachedId == id && images.length > 0) {
                    c(images);
                } else {
                    cachedId = id;
                    if (id == 1) {
                        images = [
                            { uri: "/images/data/Photo1.jpg", title: 'Photo 1' },
                            { uri: "/images/data/Photo2.jpg", title: 'Photo 2' },
                            { uri: "/images/data/Photo3.jpg", title: 'Photo 3' },
                            { uri: "/images/data/Photo4.jpg", title: 'Photo 4' },
                            { uri: "/images/data/Photo5.jpg", title: 'Photo 5' }];
                    } else {
                        images = [
                            { uri: "/images/data/Photo6.jpg", title: 'Photo 6' },
                            { uri: "/images/data/Photo7.jpg", title: 'Photo 7' },
                            { uri: "/images/data/Photo8.jpg", title: 'Photo 8' }];
                    }

                    c(images);
                }
            });
        },
        serialize: function () {
            return {
                images: images,
                id:cachedId
            };
        },
        hydrate: function (state) {
            images = state.images;
            cachedId = state.id;
        }
    };

    winjs.Namespace.define("Demo.Services", {
        imageService: imageService
    });

    applicationController.services.push(Demo.Services.imageService);

})(WinJS, Demo.Application.ApplicationController)

As you see in code above the service also exposes the same methods serialize and hydrate we met when speaking about viewmodels that serialize and deserialize service state to/from a json object.

Once we registered and added these functions, the task of invoking them when needed is contained inside Mvvm Stack’s common peristenceService.js

Here’s a fragment of serializaion code:

 //De-Serializes services that implements serialize function
            var j = 0;
            applicationController.services.forEach(function (service) {
                if (service.hydrate !== undefined) {
                    var serviceKey = "service" + j;
                    var serviceState = winjs.Application.sessionState.app[serviceKey];
                    service.hydrate(serviceState);
                }
            });

No rocket science, but it makes stack more complete and usable in real production code.

MvvmStack for WinJS Part#5

In this last post about MvvmStack I’m going to cover two aspects: Binding and Blendabilty.

Binding

I’m not going into WinJS Binding since MSDN documentation provides a lot of material, i just want to describe some binding extensions available into binding-extension.js file that extends WinJS binding capabilities.

image

Inside Binding.Extensions namespace you find:

twoWay: I’ve described it here

eventToProperty: Allows you to update a viewmodel property when a control event occurs, you can also specify a two-way mode so that when viewmodel’s property changes the control’s property is updated with new value. The demo uses it to notify the viewmodel that user flipped the image on flipview control (on section.html page) and to move to fist or last image on set using application bar’s buttons.

Here’s how is declared inside section.html page:

        <div id="flip"
            data-win-control="WinJS.UI.FlipView"
            data-win-bind="winControl.itemDataSource:images.dataSource; winControl.onpagecompleted$currentPage.value:winControl.currentPage$two Binding.Extensions.eventToProperty"
            data-win-options="{ itemTemplate : select('.flipItemTemplate') }">
        </div>

The syntax is [triggerEvent]$[viewModelProperty]:[controlProperty][$two], previous html snippet shows how, when FlipView’s onPageCompleted triggers, we update viewmodel’s currentpage.value property using control’s currentPage property in two way mode.

invokeOnEvent: Invokes a viewmodel’s method when an event occurs, passing event source as parameter to target function (sort of ‘sender’ parameter C# counterpart) if you don’t need sender, just use standard WinJS binding.

arrayBind: Allows binding to viewmodel’s properties exposed as arrays using this syntax: [sourceProp]:[property][index][property] e.g: data-win-bind="src:dataTile[0].image"

Blendability

If you, like me, use Blend for HTML tool to design the views you know that it offers an interesting interactive mode.

By clicking following button:

image

your app is run, you can play with it, then exiting from interaction mode, start modifying the live DOM acting on current live state.

Sometimes running the app and reaching the page you want to edit is tedios, that’s why i prefer to use an alternative way.

Inside defaul.html you’ll see that there’s a commented PageControlNavigator definition, this is the one i use to start app from a specific page, let’s change default.html markup this way.

<body>
    <!--<div id="contenthost" data-win-control="Application.PageControlNavigator" data-win-options="{home:'/pages/home/home.html'}"></div>-->

    <!--Uncomment this when you want to design a specific application page, dont forget to create fake data inside ViewModelLocator-->
    <div id="contenthost" data-win-control="Application.PageControlNavigator" data-win-options="{home:'/pages/section/section.html'}"></div>
</body>

Next we need to create some design-time data for editing purposes, so we uncomment the call to createDesignTimeViewModels line inside viewModelLocator.js

  //Uncomment this to create a fake design time viewmodel to use with the page associated with default.html's page navigator
    viewModelLocator.createDesignTimeViewModels();

what the function does is create some fake data when the page is loaded inside Blend.

Opening default.html in Blend now shows the page populated with fake data so you can start editing it.

image

Closing

Think I’ve covered everything you need to know to play with sample code, as stated initially there’s room for improvements and modifications. My goal was to provide an example of how to use MVVM patter in WinJS based applications.

Hope you enjoyed reading. Winking smile

MvvmStack for WinJS Part #4

In part3 we learned how to customize the components tied to our application, it is now time to investigate the ViewModels associated with each view.

Lets’ start seeing how a viewmodel is declared, inspecting homeViewModel.js, the one paired with demo application home view.

(function (winjs, mvvmStack, target) {
    "use strict";

    var HomeViewModel = winjs.Class.derive(mvvmStack.ViewModelBase, function (applicationController) {
        var data = [{ name: "Section 1", id: 1, description: "My color photos", image: "/images/phones/lumia920.jpg" },
            { name: "Sezione 2", id: 2, description: "My b/w photos", image: "/images/phones/lumia820.jpg" }];

        this._appController = applicationController;
        this.sections = new winjs.Binding.List(data).dataSource;
        this.processAll();
    },
        {
            sections: null,
            templateRenderer: function (itemPromise) {
                return itemPromise.then(function (item) {
                    // Select either normal product template or on sale template
                    var itemTemplate;
                    if (item.data.id == 1) {
                        itemTemplate = document.getElementsByClassName("productTemplate1")[0];
                    } else {
                        itemTemplate = document.getElementsByClassName("productTemplate2")[0];
                    }

                    // Render selected template to DIV container
                    var container = document.createElement("div");
                    itemTemplate.winControl.render(item.data, container);
                    return container;
                })
            },
            itemInvoked: function (e) {
                var self = this;
                e.detail.itemPromise.then(function (item) {
                    var selectedItem = item.data;
                    self._appController.selectedHomeSection = selectedItem.id;
                    //Navigates to detail page
                   mvvmStack.Navigation.navigate(target.section)
                });
            }
        });


    winjs.Namespace.define("Demo.ViewModels", {
        HomeViewModel: HomeViewModel
    });

})(WinJS, MvvmStack, Demo.Navigation.target)

As you see, it is a class inheriting from ViewModelBase that receives some external dependencies like other MvvmStack references, target urls object and, obviously, WinJS namespace.

Inside constructor we create the sections that are going to appear in home page using static data (in real world they might come from an injected external service), in this case we have section 1 and section 2, each one has its own characteristics, also note that at the end we invoke base class function processAll that marks all function exposed by the class “safe for databinding” and ensures that ‘this’ inside any instance functions safely points to class instance (if this sounds weird to you read here) please note that, at the moment, processAll doesn’t handle functions exposed by class within nested objects.

Then we have instance properties:

sections: The sections we’re going to bind to homepage listview.

templateRenderer: Since we want each section to appear differently, we created a couple of listview templates and render them through this function depending on item’s Id value.

invoked: Is the function that gets invoked when user taps a listview item, as you see, we store section id value into shared applicationcontroller object then we use mvvmstack navigation infrastructure to navigate to section page, this will create sectionViewModel first, then navigates to section.html page.

How do we pair this viewModel to homepage view?

(function (winjs,viewModels) {
    "use strict";

    WinJS.UI.Pages.define("/pages/home/home.html", {
        // This function is called whenever a user navigates to this page. It
        // populates the page elements with the app's data.
        ready: function (element, options) {
            winjs.Binding.processAll(element, viewModels.homeViewModel);
        }
    });
})(WinJS,Demo.ViewModelLocator.viewModels);

The code is quite simple, it just uses WinJS.Binding.ProcessAll to set homeViewModel as datacontext for current view, nothing more, nothing less.

Mapping viewmodel to View elements, databinding to the rescue!

Connection of HomeViewModel properties to view elements is done exclusively via databinding, as any other MVVM implementation, here’s a homepage.html fragment:

<div class="fragment homepage">
        <header aria-label="Header content" role="banner">
            <button class="win-backbutton" aria-label="Back" disabled type="button"></button>
            <h1 class="titlearea win-type-ellipsis">
                <span class="pagetitle">MVVMStack demo...</span>
            </h1>
        </header>

        <div data-win-control="WinJS.UI.ListView"
            class="homeListView"
            data-win-bind="winControl.itemDataSource:sections; winControl.itemTemplate:templateRenderer; winControl.oniteminvoked:itemInvoked"
            data-win-options="
        {
            layout: {type: WinJS.UI.GridLayout},
            tapBehavior: 'directSelect',
            selectionMode: 'none'
        }">
        </div>
    </div>

please note the use of winControl property to bind listview control’s property with viewmodel’s.

ViewModel class naming convention

In order to let the infrastructure know what are the viewmodels to persist when a suspend event occurs, viewmodel class name must be [pageName]+”ViewModel”, so if you add an “about.html” page, associated viewmodel class must be named “aboutViewModel”.

ViewModel Persistence

homeViewModel is made of static data so it is not necessary to persist it when a suspension event occurs, let’s see instead what happens inside sectionViewModel.js using following snippet:

{
        sectionTitle: null,
        images: null,
        currentPage: null,
        id: 0,
        load: function () {
            var self = this;
            this._imageService.load(self.id).then(function (photos) {
                photos.forEach(function (photoInfo) {
                    self.images.push(photoInfo);
                });
            });
        },
        first: function () {
            this.currentPage.value = 0;
        },
        last: function () {
            this.currentPage.value = this.images.length - 1;
        },
        serialize: function () {
            return {
                currentPage: this.currentPage.value
            };
        },
        hydrate: function (bag) {
            this.currentPage.value = bag.sectionViewModel.currentPage;
        }
    }

In this case the ViewModel exposes two functions: serialize and hydrate, former is invoked by persistenceService when it needs to save viewmodel’s status, latter when it is time to rehydrated it using saved informations. If your viewmodel requires state persistance just implement both functions, persistenceService.js will take care of the rest.

Closing

Once you have setup all infrastructure, here are the step required to add new page to a project:

  • 1-  Add a new pagecontrol to the project
  • 2- Add a new viemodel class named “pagenameViewModel
  • 3- Add a new property “pagenameViewModel” to ViewModelLocator’s  viewModels object
  • 4- Add a new entry to navigationTargets.js
  • 5- Add a new switch entry into ViewModelLocator’s createViewModelForUrl function.
  • 6- Modify page code behind to set ViewModel instance as page datacontext

[note] Step 3 no longer required, see here.

MvvmStack for WinJS Part #3

In this 3rd episode of the MvvmStack saga I’m going to describe how to use the set of core mvvm modules we saw in previous posts describing application dependent modules.

image

Let’s start describing navigationTargets.js

(function (winjs) {
    "use strict";

    winjs.Namespace.define("Demo.Navigation", {
        target: {
            home: "/pages/home/home.html",
            section: "/pages/section/section.html",
            noConnectivity: "/pages/noconnectivity/noconnectivity.html"
        }
    });
    
}(WinJS))

It’s a simple object, nested into Demo.Navigation namespace (use your own namespace in production code) that exposes a set of uri pointing to application pages, this allows us to centralize pages uri and pass these infos to various modules. As soon as you add new pages this object must be updated with new properties.

applicationController.js represents an optional application object shared among viewmodels, it can be used as a general data cache and it’s also persisted during suspend/resume events.

(function (winjs,mvvmStack) {
    "use strict";

    var ApplicationController = WinJS.Class.derive(mvvmStack.ApplicationControllerBase,null,
        {
            selectedHomeSection: 0,
            serialize: function () {
                return {
                    selectedHomeSection: this.selectedHomeSection
                };
            },
            hydrate: function (applicationState) {
                this.selectedHomeSection = applicationState.selectedHomeSection;
            }
        });

    var applicationController = new ApplicationController;

    winjs.Namespace.define("Demo.Application", {
        ApplicationController: applicationController
    });

})(WinJS,MvvmStack)

As you see in previous code, the object inherits from ApplicatioControllerBase class and exposes a selectedHomeSection that is used by homepageViewModel to inform sectionViewModel about what section has been selected by the user.

serialize and hydrate are functions invoked by persistence service when object must be persisted and lately rehydrated.

ApplicationController class is nested inside Demo.Application namespace.

networkService.js

While not mandatory, it is a service that monitors network connection status and using messenger object it posts messages when network connectivity status changes. The message is subscribed and handled inside connectivityService.js module

(function (winjs, messenger) {

    var _networkInfo = Windows.Networking.Connectivity.NetworkInformation;
    _networkInfo.addEventListener("networkstatuschanged", onNetworkStatusChange);
    var notifiedStatus = isInternetAvailable();

    //Handles network status changes
    function onNetworkStatusChange() {
        var mes = messenger.networkStatusChanged();
        mes.isInternetAvailable = isInternetAvailable();
        if (mes.isInternetAvailable != notifiedStatus) {
            notifiedStatus = mes.isInternetAvailable;
            messenger.send(mes);
        }
    }

    //Gets a value indicating whether internet connection is available
    function isInternetAvailable() {
        var connectivityLevel = Windows.Networking.Connectivity.NetworkConnectivityLevel.none;
        var profile = _networkInfo.getInternetConnectionProfile();
        if (profile != null) connectivityLevel = _networkInfo.getInternetConnectionProfile().getNetworkConnectivityLevel();
        return connectivityLevel === Windows.Networking.Connectivity.NetworkConnectivityLevel.internetAccess;
    }

    winjs.Namespace.define("Demo.Application.Services.Network", {
        isInternetAvailable: isInternetAvailable
    });

})(WinJS, Demo.Application.Messenger)

connectivityService.js is a completely optional component that in the demo application handles connectivity changes messages navigating to a static noConnectivity.html pagecontrol. Your application can freely ignore this module and handle connectivity changes in a total different way, all you need to do is to subscribe the message as connectivityService does.

viewModelLocator.js takes care of creating the viewModels associated with application pages, it’s a class that derives from viewModelLocator base and overrides createViewModelForUrl function.

createViewModelForUrl is the core function that take care of creating a viewModel before page gets loaded, depending on target url.

 createViewModelForUrl: function (uri) {
                switch (uri) {
                    case target.home:
                        this.viewModels.homeViewModel = this.viewModels.homeViewModel || new Demo.ViewModels.HomeViewModel(applicationController);
                        break;
                    case target.section:
                        this.viewModels.sectionViewModel = new Demo.ViewModels.SectionViewModel(applicationController, services.imageService);
                        this.viewModels.sectionViewModel.load();
                        break;
                }
            },

The snippet demonstrates how a single instance viewModel is creates for home page, while when user navigates to section page, a SectionViewModel instance is instantiated and related images loaded.

Since each viewModel becomes a property of viewModels object, when a new ViewModel is added the object must be updated adding a property that matches ViewModel name.

this.viewModels = {
            homeViewModel: null,
            sectionViewModel: null
        };

Note: I’m sure code can be refactored to avoid this step, maybe in a future release… Smile

The code also includes a createDesignTimeViewModels function, I’ll describe it in a forthcoming post regarding Blendability.

Closing

In next post we’ll analyze pages ViewModels, how to create and pair them with related View.

MvvmStack for WinJS Part #2

Following part 1, let’s now see how the code is structured:

image

Inside mvvm folder there are all the files that provides core functionality, this means that you can reuse this files in different apps without modification.

Inside pages folder there are, as usual, the PageControls representing application pages, as you see in this case there’s a new actor: the associated viewmodel (e.g homeViewModel.js)

Infrastructure bootstrapping

The demo is based around HTML Navigation Application template, if you need to create a new app, just select it and let Visual Studio 2012 create all required files for you, then delete navigator.js file since it is already included inside mvvm folder in a slightly modified version.

Dependencies

Looking at the code you’ll see that I like to explicitly indicate what are each file dependencies passing them to module self-invoking function, that implies that modules must be loaded using a prefixed sequence otherwise dependency would become unresolved.
The sequence is available inside default.html file that represents application master page:

<head>
    <meta charset="utf-8" />
    <title>MvvmStack</title>

    <!-- WinJS references -->
    <link href="//Microsoft.WinJS.1.0/css/ui-dark.css" rel="stylesheet" />
    <script src="//Microsoft.WinJS.1.0/js/base.js"></script>
    <script src="//Microsoft.WinJS.1.0/js/ui.js"></script>


    <link href="default.css" rel="stylesheet" />
    
    <!--MVVM-->
    <script src="../../js/mvvm/applicationControllerBase.js"></script>
    <script src="../../js/mvvm/viewModelLocatorBase.js"></script>
    <script src="../../js/mvvm/viewModelBase.js"></script>
    <script src="../../js/mvvm/binding-extensions.js"></script>
    <script src="../../js/mvvm/messenger.js"></script>
    <script src="../../js/mvvm/navigator.js"></script>

    <script src="default.js"></script>
    <script src="../../js/applicationController.js"></script>
    <script src="../../js/navigationTargets.js"></script>
    <script src="../../converters/converters.js"></script>

    <!--core services-->   
    <script src="../../js/networkService.js"></script>

    <!--data services-->
    <script src="../../js/imageService.js"></script>

    <!--Viewmodels-->
    <script src="../home/homeViewModel.js"></script>
    <script src="../section/sectionViewModel.js"></script>

    <!--services-->
    <script src="../../js/ViewModelLocator.js"></script>
    <script src="../../js/mvvm/persistenceService.js"></script>
    <script src="../../js/mvvm/navigationService.js"></script>

</head>

As evident mvvm core modules are loaded first, then modules that depends/inherits from core modules then other optional core services like networkService (a service that monitors network connection status) followed by page viewmodels and ending with modules that require all modules accessibility like ViewModelLocator, PersistenceService and NavigationService.

Core Mvvm modules

Let’s now see what are the core mvvm modules:

  • ApplicationControllerBase.js

  • Is the base class for ApplicationController, an object that can be shared among ViewModels that I use as a quick way to pass informations among them, it’s state is normally persisted when app gets suspended. Obvisouly it is an optional part but demo shows how you can use it to share parameters from home page to section page.

  • binding-extensions.js

  • This is a general binding helper module an not tied to Mvvm, it contains helper functions that add two-way binding, two-way binding triggered by an event and a event to method invoker. If you want to extend WinJS binding this file would help you.

  • messenger.js

  • This represents a generic message broker allowing you to send messages among loaded modules, app uses it to navigate to a “no connectivity” page when connection drops. (try it running the app then activating flight mode) It includes a couple of predefined messages: networkStatusChanged and navigatedBack.

  • navigationservice.js

  • This is the modules that handles page navigation, it uses WinJS navigation infratructures but it takes care of instantiating the page viewmodels when required.

  • navigator.js

  • This is the same navigator objects that you get when you choose a WinJS navigation template as starting Javascript template in Visual Studio 2012, it has been slightly modified to send a navigatedBack message when uses navigates back from a page, the message instruct the infrastructure that associated viewmodel should not be persisted in case of suspension.

  • persistenceService.js

  • This is the service that, when a suspension request occurs, serializes applicationController and all viewModels implementing serialize method. It also re-instantiate viewmodels and rehydrates them when application resumes.

  • viewModelBase.js

  • Base class for all viewmodels, it includes a processAll function that marks all viewmodel’s function as ‘safe for processing’ and set ‘this’ context to viewmodel instance.

  • viewModelLocatorBase.js

  • Base class for ViewModelLocator, a class that takes care of creating/deleting page viewModels.

Closing

That’s all for now, on next episode we’ll see what you need to customize to use the stack in your app.

Older Posts »