Sunday, August 26, 2012

Getting Started w/ Windows 8, MVVM Light and EventToCommand

,
Now that Windows 8 and Visual Studio are in RTM I wanted to put together a quick entry for those Windows Phone developers making the transition to Windows 8 development with their MVVM Light skills.

Laurent Bugnion, is the creator of the MVVM Light toolkit and I, as well as many others, have been using this for Windows Phone development for a while now.  I am porting on of my applications to Windows 8 and wanted to take the knowledge of this toolkit to the new platform hoping that there were either some new enhancements and/or not many changes so that I could just go.  Well that was the deal.

MVVM Light Toolkit for Windows 8 RTM

The latest installer for the toolkit, "MVVM Light Toolkit V4 RTM", is available from CodePlex. According to Laurent's blog it is a side by side install with previous versions:

MVVM Light for Windows 8 is a side-by-side install with the standard MVVM Light V3 or V4 beta. Simply download and run the MSI from Codeplex. As usual, the last step of the installation performs a “/setup” of Visual Studio to actualize the project template cache, and unfortunately this last step can last very long. Please be patient and don’t cancel before the end! The installation process is very similar to that described on the MVVM Light installation page (except that there is no NuGet installer for VS11 yet).
The following link states the summary of the ported components from the previous versions, but I'll paraphrase here:

  • ObservableObject including all ways to raise PropertyChanged. 
  • ViewModelBase including all ways to raise PropertyChanged. 
  • Messenger including all message types except DialogMessage (see below). 
  • RelayCommand with and without parameter. 
  • SimpleIoc which might well be the very first IOC container working on Windows 8. 
Man do I love the SimpleIoc! Makes adding the new views soooo much easier than in the Windows Phone version.

There are a few missing components, one of which is EventToCommand, however thanks to a new friend I have made, Joost van Schaik (see his blog here),  there is a solution to that and it's available as a nuget package with some additional behavior features I encourage you to look into but I'll at least cover the EventToCommand features he offers.

Getting Started

MVVM Light Project Template

After installing the toolkit you will see that there is a new project template available in the Visual Studio 2012 New Project Dialog

Noted as "Windows Metro Style"

Name the project "MvvmLight_Walkthrough" and click Ok.

The project template is simple, but add some new features that were not in previous versions of the toolkit. In the Solution Explorer you'll notice a Design folder with a class called DesignDataService. This is a great feature; the default template putting in a design data class repository.

Second, as in the past version of the toolkit there is the normal ViewModelLocator class, but in this version there is new feature - SimpleIoc, a container class which if you are like me had everything else in a container for DI with the exception of the ViewModels unless you rolled your own.


public class ViewModelLocator

    {

        static ViewModelLocator()

        {

            ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);



            if (ViewModelBase.IsInDesignModeStatic)

            {

                SimpleIoc.Default.Register<IDataService, Design.DesignDataService>();

            }

            else

            {

                SimpleIoc.Default.Register<IDataService, DataService>();

            }



            SimpleIoc.Default.Register<MainViewModel>();

        }



        /// <summary>

        /// Gets the Main property.

        /// </summary>

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance",

            "CA1822:MarkMembersAsStatic",

            Justification = "This non-static member is needed for data binding purposes.")]

        public MainViewModel Main

        {

            get

            {

                return ServiceLocator.Current.GetInstance<MainViewModel>();

            }

        }



        /// <summary>

        /// Cleans up all the resources.

        /// </summary>

        public static void Cleanup()

        {

        }


And last, in the Model folder, Laurent has been kind enough to also include an IDataService interface and DataService class to show in the example how to use the real time and design time data models. These are all wired up in the ViewModelLocator as show above.

Now if we simply run the application you should get the following to make sure it's all good to go!

Running in the Simulator

As you may or may not notice, this is not to dis-similar from the previous project template test from the previous version.

MainViewModel

The binding of the ViewModel to the View is the same as it was in the previous model and there are no noticeable changes to the ViewModelTemplate.  On thing to note is that all options for RaisePropertyChanged are included in this release where as in the previous version you would have to get the "Pre-release" version from nuget in order to use them. For example, the built in template puts in the following:


/// <summary>

        /// The <see cref="WelcomeTitle" /> property's name.

        /// </summary>

        public const string WelcomeTitlePropertyName = "WelcomeTitle";



        private string _welcomeTitle = string.Empty;



        /// <summary>

        /// Gets the WelcomeTitle property.

        /// Changes to that property's value raise the PropertyChanged event.

        /// </summary>

        public string WelcomeTitle

        {

            get

            {

                return _welcomeTitle;

            }



            set

            {

                if (_welcomeTitle == value)

                {

                    return;

                }



                _welcomeTitle = value;

                RaisePropertyChanged(WelcomeTitlePropertyName);

            }

        }

Noticeably where RaisePropertyChanged is using a string value, one of the options now available in the release is to remove the  WelcomeTitlePropertyName variable and then change



RaisePropertyChanged(WelcomeTitlePropertyName);


to

RaisePropertyChanged(() => WelcomeTitle);


The other nice benefit here is that the template has also put in the wiring for injecting the IDataService into the constructor for the ViewModel.  Some of these little thing we developers either take for granted that someone has gone through the trouble of putting the plumbing in there or call it the boring work that has to be done before we get the real work done.  You can easily put other dependencies in the constructor here and then just add the mappings in the constructor of the ViewModelLocator by simply registering the types with the SimpleIoc container.


public MainViewModel(IDataService dataService)

        {

            _dataService = dataService;

            _dataService.GetData(

                (item, error) =>

                {

                    if (error != null)

                    {

                        // Report error here

                        return;

                    }



                    WelcomeTitle = item.Title;

                });

        }



Now What?.

A simple example here is to add some content to the MainPage and see how we navigate to a second view.  I won't bore you with the details of adding in the controls to the page but here's what the page should look like when you're done. 

Added a little MvvmLight color for fun

EventToCommand

Now lets just add a prompt to the submit button. But wait, what where's my EventToCommand???  Sure with the button there is a Command property and you can set that to an ICommand in the ViewModel and everything is happy.  But, there are plenty of controls, both baked into WinRT and third party controls that do not have that property. So, for simplicity sake I'm using this control and will get the EventToCommand back in your toolbox, or your Joostbox I should say.

Off to Nuget!

I had this issue where I was looking for the behaviors when porting an app I was working on and could find the dang behaviors in Blend so I went to nuget and did some searching and there wasn't anything that was shaking my fancy. Then I came across Joost van Schaik (see his blog here) and his WinRTBehaviors library and just so happens I hit him in the middle of uploading the nuget package for Win8nl.

Now this is a package of Behaviors that was originally a Windows Phone 7 library and It's now growing in its own direction and now contains some Windows 8 specific stuff (according to nuget). So let's get it installed real quick.

Install the package by typing the following into the Nuget Package Manager Console or searching for Win8nl in the package explorer.

PM> Install-Package Win8nl

It will add the library and the necessary dependencies to the project, which include WinRTBehaviors. For more information on the other behaviors there check out Joost's blog.

Adding EventToCommand 

First, lets add the references to the XAML page:

xmlns:WinRtBehaviors="using:WinRtBehaviors"

xmlns:Win8nl_Behavior="using:Win8nl.Behaviors"

Next, locate the button control and add the following inside the button XAML:


            <Button x:Name="btnSubmit" Content="Submit"    

                    FontFamily="{StaticResource MyFont}" FontSize="{StaticResource MyFontSize}"

                    HorizontalAlignment="Center" Margin="0,20,0,0">



                <WinRtBehaviors:Interaction.Behaviors>



                    <Win8nl_Behavior:EventToCommandBehavior Event="Tapped"       

                                                  Command="AreYouSureCommand"        

                                                  CommandParameter="{Binding MyName}"/>



                </WinRtBehaviors:Interaction.Behaviors>



            </Button>


Now, open the MainViewModel.cs code and we can add the command for the new behavior here when the button is tapped.

As usual the Command property is expecting an ICommand, add the following code to the MainViewModel and return a new instance of RelayCommand to execute whatever behavior you wish.  In this example, I'm just doing a little popup to show whatever the user input into the myName TextBox.


public ICommand AreYouSureCommand

        {

            get

            {

                return new RelayCommand<string>((p) =>

                {



                    var msg = new MessageDialog(string.Format("Hi there {0}", p));

                   

                    msg.ShowAsync();



                });

            }

        }


See the result here:


And that is EventToCommand for MVVMlight for Windows 8!

There are many more behaviors in the WinRTBehaviors library that you should take advantage of, for me the most notable ones being FlipViewPanoramaBehavior and NavigationService being ported to Windows 8.



19 comments to “Getting Started w/ Windows 8, MVVM Light and EventToCommand”

  • August 26, 2012 at 8:40 PM
    ArchieCoder says:

    Great article! The step by step guide is just perfect to understand well the topic about adding the EventToCommand.

    Thank you
    ArchieCoder

    delete
  • August 26, 2012 at 10:43 PM
    Anonymous says:

    Great post! I like this step by step guide on how to use EventToCommand in a Windows 8 app.

    Thank you!
    ArchieCoder

    delete
  • September 21, 2012 at 12:44 AM
    Anonymous says:

    Hi, thanks for the post, I am new to MVVM. Is it possible if you can attach the source code?

    Or, actually my problem is I don't know how to get the textbox value.

    How do you define the [MyName]?CommandParameter="{Binding MyName}"

    I actually do it like
    CommandParameter="{Binding Text, ElementName=txtBoxXName}", but I always get null value in the ModelView.

    Thanks alot.

    delete
  • September 21, 2012 at 10:09 AM
    Shayne Boyer says:

    The CommandParameter="{Binding MyName}" is a property in the ViewModel.

    It would be represented in the ViewModel as:

    public string MyName
    {
    get {return _myName;}
    set {_myName = value; RaisePropertyChanged(() => MyName);}
    }

    And in the xaml the Text property of the TextBox is bound to this as well.

    delete
  • September 26, 2012 at 8:41 AM
    Anonymous says:

    Hi,

    Very interesting post, good job.

    I'm using EventToCommand Behavior. I'm adding the behavior to an ItemTemplated UIElement.

    The problem is :the datacontext of that element is a "child viewmodel", however i want to trigger a command from the parent viewmodel. In that case, the command property of the behavior can't find the command.

    How can i access a command from an ancestor viewmodel ?

    Thank's

    delete
  • September 26, 2012 at 10:17 AM
    Anonymous says:

    I'd like to pass 'SelectionChanged' event from ListView to my view model.
    I also need parameter passed with this event (SelectionChangedEventArgs).

    Is it possible to do this with Win8nl library ?

    delete
  • September 26, 2012 at 11:22 AM
    Shayne Boyer says:

    RE: "How can i access a command from an ancestor viewmodel ?"

    You may want to implement the messaging functionality in MVVM Light as the commands are only available from the directly bound ViewModel

    delete
  • September 26, 2012 at 11:24 AM
    Shayne Boyer says:

    RE: "SelectionChanged"

    Yes. Here is an example.


    delete
  • October 25, 2012 at 3:33 AM
    XYLIGAN says:

    Hi, thank you for a great article!
    It helps me to start.
    Now i am trying to use this approach for event LoadedCompleted in WebView but i get unspecified error =(

    http://stackoverflow.com/questions/13012967/bind-events-to-mvvm-model-in-windows-8

    delete
  • October 26, 2012 at 10:19 AM
    Anonymous says:

    Shayne,

    You mention "Yes. Here is an example" above but no link or code.

    I am trying to use a ListBox to trigger SelectionChanged but no trigger is fired. The xaml code is highlighted and shows an error//warning stating:

    "A value of type EventToCommandBehavior cannot be added to a collection of type ObservableCollection"

    My list is bound to

    public IList Items
    ...







    Any thoughts or suggestions would be appreciated.

    Declan

    delete
  • October 26, 2012 at 10:22 AM
    Anonymous says:

    Oops xaml code removed above!

    Here it is with brackets replaced by -:

    -ListBox
    x:Name="ItemList"
    ItemsSource="{Binding Items}"
    SelectedItem="{Binding SelectedItem}"
    -WinRtBehaviors:Interaction.Behaviors>
    -Win8nl_Behavior:EventToCommandBehavior
    Event="SelectionChanged"
    Command="{Binding itemSelectionChangedCommand, Mode=OneWay}"
    CommandParameter="{Binding SelectedItem, ElementName=ItemList}" /-
    -/WinRtBehaviors:Interaction.Behaviors-
    -/ListBox

    delete
  • November 1, 2012 at 3:04 PM
    Shayne Boyer says:

    @Declan

    Have you gotten the latest version of win8nl and winRTbehaviors from nugget? This should addressed now.

    delete
  • November 28, 2012 at 1:58 PM

    this is helpful thing especially if you like tattoos designs .

    delete
  • December 4, 2012 at 2:52 AM
    Anonymous says:

    Hi Shane,

    I'm having the same problem as Declan above. I've gotten the latest versions of in8nl and winRTbehaviours from NuGet.

    bk

    delete
  • December 13, 2012 at 3:37 AM
    Anonymous says:

    Hi all,
    I've got the same problem.
    Trying to bind a command to the event SelectionChanged works, passing paramater bound to the viewModel works, but passing SelectedItem of GridView seems to be always null.

    delete
  • This comment has been removed by a blog administrator.
    January 27, 2013 at 6:27 AM
    Anonymous says:

    This comment has been removed by a blog administrator.

    delete
  • January 28, 2013 at 11:54 AM
    Shayne Boyer says:

    Font size for code has been adjusted... Ctrl+ is also available in most browsers for zooming as well. Thanks for the note.

    delete
  • April 26, 2013 at 6:11 AM

    Hi Shayne Boyer, great post, i am facing problem after installing Win8nl package from NuGet. When i run the app, the directly exit and alert saying: "Unable to activate Windows Store app" & "The app didn't start". Please can you help on this?

    delete
  • November 1, 2013 at 2:17 AM
    janhannemann says:

    Fresh installed nugget package and I get this the same error as they others when I try




    On the page level.

    delete
Powered by Blogger.
 
Creative Commons License
TattooCoder.com by Shayne Boyer is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.