While I’m not a zealot on the topic, I do believe that MVVM offers one of the best patterns for Windows Phone development and so, moving forward, the Windows Phone From Scratch series will incorporate MVVM in general, and the MVVM Light Toolkit in particular.
I’m more than convinced that MVVM is an essential pattern for Windows Phone Development; and while there are many excellent frameworks to make MVVM development easier, the one I personally prefer to work with is the MVVM Light Toolkit and so it is the one I’ll focus on.
I make the case for MVVM in this article, and so I won’t rehash that material here. Instructions for installing MVVM Light Toolkit are available here.
I will not assume any background with MVVM or with the Toolkit beyond those two links. That is, I’ll assume you’ve loaded the toolkit and created your very first, single page MVVM application, but not more than that.
In that spirit, let’s begin by creating a two page MVVM application. This immediately forces us to talk some issues I’ve not found in other introductory tutorials, and will, in the next tutorial bring up even more interesting topics, such as behaviors and messages(!)
Creating the Application
To begin, open Visual Studio and click on New Project. In Installed Templates select MVVMLight(WP7), and make sure that you see the option for MvvmLight (WP7). If not, please refer to the resources above to fix your installation.
Select MvvmLight and name the project MvvmLightNavigationBehaviorAndMessages. Run the application before touching the code, you’ll find that the application name and page name have been set for you and that there is a text block proclaiming “Welcome to MVVM Light” (!) This is Laurent’s way of helping ensure that all is working well.
Linking the View and Its View-Model
Look in MainViewModel.cs and you’ll find three string properties: ApplicationTitle, PageName and Welcome. These serve as properties to bind to on MainPage.xaml,
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="24,24,0,12"> <TextBlock x:Name="ApplicationTitle" Text="{Binding ApplicationTitle}" Style="{StaticResource PhoneTextNormalStyle}" /> <TextBlock x:Name="PageTitle" Text="{Binding PageName}" Margin="-3,-8,0,0" Style="{StaticResource PhoneTextTitle1Style}" /> </StackPanel> <Grid x:Name="ContentGrid" Grid.Row="1"> <TextBlock Text="{Binding Welcome}" Style="{StaticResource PhoneTextNormalStyle}" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="40" /> </Grid>
All that is necessary is for MainPage to set MainViewModel to be its DataContext, which is accomplished on the 17th line of the file (at the end of the opening tag for the PhoneApplication page)
<phone:PhoneApplicationPage x:Class="MvvmLightNavigationBehaviorAndMessages.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone" xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" FontFamily="{StaticResource PhoneFontFamilyNormal}" FontSize="{StaticResource PhoneFontSizeNormal}" Foreground="{StaticResource PhoneForegroundBrush}" SupportedOrientations="Portrait" Orientation="Portrait" mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768" shell:SystemTray.IsVisible="True" DataContext="{Binding Main, Source={StaticResource Locator}}">
Notice that this does not set the data context directly, but rather uses the StaticResource Locator.
ViewModelLocator
It is worth diving into how this works, as the ViewModelLocator is central to the MVVM Light Toolkit. This is one very good way, though not the only way, that you can set up the relationship between a view (MainPage) and its view model (MainViewModel)
The static resource Locator is defined in App.xaml
<Application.Resources> <vm:ViewModelLocator x:Key="Locator" d:IsDataSource="True" /> </Application.Resources>
Finally, in the ViewModelLocator.cs file (created in the ViewModel folder when you created the application) you’ll find that the ViewModelLocator constructor calls CreateMain() which in turn sets the static property _main which is of type MainViewModel.
The net effect is to link (silently and without your intervention) MainPage to its view-model.
When it is time to add a second page, as you’ll soon see, you have a bit of work to do, but it is all spelled out for you and there are code-snippets that make the work trivial. Or nearly so.
Adding A Second Page
Let’s go most tutorials on MVVM Light one step further, and actually create that second page, and wire it up (I’m not sure that no other tutorial has done this yet, but I was hard-pressed to find one that did).
First, right-click on the project and create a new folder named Views. Then right click on Views and click on Add->New Item. Select MVVM Page (WP7) and name the new page Page2.xaml.
Hey! Page 2 is identical to MainPage. That is because the bindings are the same and if you look closely you’ll see that it was “born” with the datacontext set to main. Let’s fix that.
Create a View-Model page for Page 2 named Page2ViewModel in the ViewModel folder (of type MvvmViewModel (WP7) ).
Add the following public properties to the new View Model file:
public string ApplicationTitle { get { return "MVVM LIGHT"; } } public string PageName { get { return "Page 2"; } } public string Welcome { get { return "Welcome to Page 2"; } }
Now let’s connect them up. Start by changing the name in the Datacontext in the view from Main to Page2ViewModel.
Using the Code Snippets
Next, open the ViewModelLocator.cs file and scroll down to just below the constructor. Here you can add most of the necessary code by using the mvvmlocatorproperty snippet. Just type in the word and hit tab. Overwrite with the name of the new type and the name of the local instance (in this case Page2ViewModel and _page2ViewModel. Nearly all the code you need is created for you. Just add CreatePage2ViewModel() to the constructor.
Return to Page2.xaml and note that the page now reflects the new properties in the View Model.
Next Step: Navigation with Behaviors and Messaging
What remains is to add a button on the first page that will cause a navigation to page 2. This can certainly done in code-behind, but there is a better way: using behaviors and messages. We’ll take that up in the next mini-tutorial.
11月12日《中国青年报》报道了安徽黄山市国税局,花60多万买茶叶的“杯中”奇观。60多万的茶叶想来一定让人津下生香,不过,那是过去,现在黄 现货茶叶 山市国税局恐怕是要流汗脊背了。 新闻中说:一份公开转让说明书泄露惊天秘密,黄山市国税局今年1到7月花费61.99万成为黄山六百里猴魁茶业股份有限公司的主要客户。黄山市国税局回应称,购茶的相关数据,涉事公司并未与他们沟通过,他们认为“严重失实”。 是“百里猴魁”数据造假,还是国税局“好茶”不怕开水烫? 这份公开说明书,其实是“新三板”的申报稿。很多人不太明白“新三板”是个啥意思,极简言之,“新三板”是主要针对中小企业的,一个全国性的非上市股份有限公
your page is out of date compared to what appears in mvvm light as of today.
Your very first code does not appear in MainViewModel.cs. Those three properties, whatever. Consider updating this or pulling it until then.
public string ApplicationTitle
{ get
{ return “MVVM LIGHT”; }
}
… etc
in the ViewModel???
Shouldn’t there be a Page2DataItem holding the model information?
After following all the steps it worked. When I tried to create a third page it didn’t and now I’m trying to start from scratch and not working 🙁
Fixed, don’t know what was the reason….just restarted computer and baam !
Addendum: First of all, we’re trying to do what you’ve done here, but in a WPF project instead of a WP7 project.
We’ve got another question. In the traditional MVVM pattern, each view has it’s own view-model, containing the “code-behind” for that view. After completing your tutorial, clicking the button takes us to page 2, which fires off the relay command, which fires off the MessageBox, but the code-behind is all in the view-model for the main page. So, what are we missing?
I think I see our mistake. We’re getting the message box dialog box, not the second window/page.
“Type in the word”? What do you mean? When I type in “mvvmlocatorproperty” and press tab, all I get is: MvvmLightNavigationBehaviorAndMessages. I don’t get any code snippet doing anything for me. Perhaps I don’t have code snippets enabled? I don’t know, as I’ve never used them before.
“Hey! Page 2 is identical to MainPage. That is because the bindings are the same and if you look closely you’ll see that it was “born” with the datacontext set to main. Let’s fix that. ”
I have recently downloaded the mmvlight v3 and whenever I create a new mvvmView, the new file is not like the main. In addition, the text properties are already set with the WP default text…
Any ideias?
I had the same problem. I looks like they’ve removed the MVVM Page template from the MVVM light installation and replaced it with just a MVVM View template.
To match the original MVVM Page template you’ll want to copy and paste the grid from Main.xaml into page 2 (replacing the previous grid there) and change hte Page2.xaml databinding at line 17 to Main
Holy boilerplate code… yuck, I’ll stick to non-ui work…
Hi Jesse,
I would like to give a suggestion about when to initialize the viewmodellocator.
When you add it as an application resource by inserting the xaml:
Then the viewmodel is initialized before the Application_Launching method is executed.
Inside this method however, you normally would like to add code to initialize your model that you deserialize from isolated storage.
The problem arises when constructors inside your viewmodel classes are trying to use the Model, which at that time isn’t initialized yet.
Therefore I would like to suggest to postpone the addition of the ViewModelLocator to the resources after the model has been initialized and loaded.
private void Application_Launching(object sender, LaunchingEventArgs e)
{
ToyBankModel.Load();
Resources.Add(“Locator”, new ViewModelLocator()); // Now, the constructors of the viewmodels have access to a initialized model state
}
–Andre
As a remark on my own reply I would suggest to leave the resource where it resides in the App.xaml but only start creating the viewmodels after you have loaded the model from isolated storage:
private void Application_Launching(object sender, LaunchingEventArgs e)
{
ToyBankModel.Load();
ViewModelLocator.CreateViewModels(); // create the viewmodels after the model has been loaded
}
This walk through of MVVM Light is GOLD! Thanks Jesse
@steven no, he’s right, there are no MVVMPage templates in the zip file
@Richie Scott
you need to add the itemtemplates to the template location in visual studio as you did with the project templates…
Good Article – Is there a part two? If so please would someone indicate such.
@Matthias
Yes, you are supposed to combine the cleanup methods.
A quick note: In the version of MVVMLite I’m learning on, for the mvvmlocatorproperty, in addition to “Page2ViewModel” and “_page2ViewModel”, I had to type Page2ViewModel one more time in order to get the “CreatePage2ViewModel” method.
The other problem I’m having is that the mvvmlocatorproperty snippet adds a “Cleanup()” method for each property, which of course throws a “Type [etc] already defines a member called “Cleanup” w/ the same parameter types” error.
I *think* I’m supposed to add the “ClearPage2ViewModel()” to the single “Cleanup” method, but I would love it if that were spelled out for me.
This helped me. Thanks!
Finally, someone taking it step by step for us beginners.
Really hoping to see the next step very soon.
Great stuff and thanks from Indy.
When adding a new page or a new viewmodel I don’t see the items MVVM Page (WP7) or MvvmViewModel (WP7).
Any ideas? Everything else (templates and snippets) work fine.
Thanks
FYI: Under Using the Code Snippets, per:
“Overwrite with the name of the new type and the name of the local instance (in this case Page2ViewModel and _page2ViewModel.”
Just wanted to note that it appears you also need to overwrite the corresponding comment, replacing “ViewModelPropertyName” with “Page2ViewModel.” Otherwise there will be no CreatePage2ViewModel() -just a CreateViewModelPropertyName() method.
Thanks alot, I was stuck at this step
Really helped understanding MVVMLight and Behaviors.
Hey Jesse,
please keep up your nice work! 🙂
Greetings from Germany
Jesse,
I also can’t wait for the next installment. Your piece of the “Firestarter” was great and now I’m hooked! Keep up the great work!
Thanks and Happy New Year!
@Bryon Barnard
Byron, add it to the constructor for the Locator.
Where is the constructor for the locator ? Also, what _main does ? I still don’t understand whats the purpose of the underscore. Thanks in advance.
Found it, problem was at had to rename sometihng to Page2ViewModel. Awesome tutorial thanks !
Jesse, you add “CreatePage2ViewModel()” to which constructor?
Great write up Jessie. The only problem with reading part 1, is that I already want to go on to part 2 and it’s not out yet! I had the same problem watching 24. Much easier to wait for it to come out on DVD and watch it all at once. Maybe I’ll wait for your blog’s “boxed set” edition. 😉
As always – keep up the great work!