Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

One ViewModel and multiple views

I've got some questions about Windows Phone 8, and the MVVM pattern.

  1. I'm wondering how I can bind elements from many displayed pages to one ViewModel (there is only one ViewModel, because I want to use the Facade Pattern).

  2. Every tutorial I saw includes code where the ViewModel and Model are in static fields. I'm not sure about correctness of this. Can someone tell me where in a WP8 app the new Model and ViewModel should be created to do it right? (By "right" I mean also that I can bind elements from multiple pages to this one ViewModel.) I was considering the App.xaml.cs file but still not sure.

Thanks for your help!

like image 753
p_piorkowski Avatar asked Oct 16 '13 22:10

p_piorkowski


2 Answers

I've been recently bothering myself with similar questions. In the end I used App.xaml.cs to create the viewmodel.

Answers

Yes, it is a correct way to create a static viewmodel in App.xaml.cs, because the App class is accesible from any page in the application, it is also correct to declare them static, because you're going to want to access it without creating the instance of App, and And as Tariq wrote in his answer:

ViewModel and Model are static fields so the values are not destroyed if they go out of scope. This further enables easy updating from multiple pages.

EDIT: Just be careful, when you're browsing between the pages, and navigating back, the binding does not automatically restore once you're going back to page in memory.

How to

I added this to the App.xaml.cs next to the definition of RootFrame:

private static MainViewModel viewModel; //not sure how your viewmodel class is named
public static MainViewModel ViewModel   //and a property to access it from
{
  get
  {
    if(viewModel == null)               //which creates the viewModel just before
       viewModel = new MainViewModel(); //it's first used
    return viewModel;
  }
}

And when I wanted to bind something in my page, jst added this to the contructor of the page (after InitializeComponents();):

DataContext = App.ViewModel;

Whe you want to bind, you better set the binding in an OnNavigatedTo() (provided it's not too resource expensive to build - if it's going to take more than some time or resources, you should consider reworking your ViewModel so it loads over time).

Just Add this to your page:

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        base.OnNavigatedTo(e);             //not needed, base method is empty and does nothing
        DataContext = null;                //important part, whenever you navigate, refreshes the ViewModel - no deletion, just resetting of the DataContext, so the page won't get stuck
        DataContext = App.ViewModel;      //and finally the resetting
    }

To explain what this code does and why i edit my code like this:

  • When making my App, I've been concerning myself with in-App navigation, like backbrowsing - and when i pressed the hardware back button and got to previous site, the values were unchanged, even though i changed them in the page i backbrowsed from. They were good in the Model, but did not bind correctly when "backbrowsing".

As i tried to solve it, it came to me in the end.

All you need to do to refresh the binding is:

  • set it again, and since the contructor of the page is not called when backbrowsing, the only place to refresh it was OnNavigatedTo() event.

  • I tested It and it works

(So, when the first page is created and tries to bind data, the viewmodel is autmatically created just by a get request :) )

And in xaml, i can just bind by:

<TextBlock text="{Binding SomePropertyNameFromViewModel}" />

or

<TextBlock text="{Binding SomeModelInViewModel.ItsProperty}" />

or for example:

<ListBox IemSource="{Binding SomeCollectionInViewModel}">
...rest omitted for brevity...

et cetera...

And the best thing? It works and it's fairly easy. I'm using it for ViewModel with several commands and about 6 or 7 models containing properties and collections for binding, that are getting populated as user goes through the app and specifies what to load.

P.S.: From what i get this is the way to do it, even basic WP pivot app does it like this.

You can check yourself if you create an empty pivot app an look into App.xaml.cs, there is going to be a viewmodel created just like this. And it's accesible from every page.

like image 98
mishan Avatar answered Oct 06 '22 18:10

mishan


I am not too experienced but from what work I have done::

Yes you can use the App.xaml.cs file to access the ViewModel from multiple pages. The ViewModel will receive updates from all pages. That's the beauty of it!

ViewModel and Model are static fields so the values are not destroyed if they go out of scope. This further enables easy updating from multiple pages.

like image 26
Tariq Avatar answered Oct 06 '22 18:10

Tariq