Dimitris
Dimitris

Reputation: 755

Prism Xamarin Forms View is not updated after changing the model in OnNavigatedTo

Prism 6.3.0

I'm navigating to a View and I'm settings some properties of the Model in the OnNavigatedTo method. The problem is that the view is not updated after setting the properties of the model.

My model looks like this

public class Person
{
    public string Name { get; set; }
    public string Email { get; set; }
}

In my ViewModel

public Person Model
{
    get => _model;
    set => SetProperty(ref _model, value);
}

The OnNavigatedTo method is

public void OnNavigatedTo(NavigationParameters parameters)
{
    var personModel = (Persom)parameters["Model"];

    _model.Email = personModel.Email;
}

And in XAML

<Entry Text="{Binding Person.Email, Mode=TwoWay}">
</Entry>

I also tried the OnNavigatingTo method but I didn't have the expected results. So what should I do in order to update the view with the new data when I'm navigating to the view?

Upvotes: 0

Views: 1471

Answers (2)

lowleetak
lowleetak

Reputation: 1382

Set the model using the setter instead of the private variable.

public void OnNavigatedTo(NavigationParameters parameters)
{
    var personModel = (Person)parameters["Model"];

    Model.Email = personModel.Email;
}

Also, your XAML should be change from Person.Email to Model.Email

=========== EDITED ============

You only set the email of model which do not call SetProperty, so the views will not get updated with the new email set. In order to have the views update, you will need to set the Person model to the following:

public class Person : BindableBase
{
    public string Name { get; set; }

    private string _email;
    public string Email
    {
        get { return _email; }
        set { SetProperty(ref _email, value); }
    }
}

Or instead of just setting the email in OnNavigatedTo, you can set the Person object.

public void OnNavigatedTo(NavigationParameters parameters)
{
    var personModel = (Person)parameters["Model"];

    Model = personModel;
}

Upvotes: 1

Dan Siegel
Dan Siegel

Reputation: 5799

You can see a full working example of how to do this with the Prism Quickstart Templates.

There are a few key things that you need to do:

Binding directly to your Model's properties is a wonderful thing to do (it's frankly something I do in all of my apps & demos). However, binding directly to your Model's properties means that you need to ensure that your Model is Observable (implementing INotifyPropertyChanged).

public class Person : BindableBase
{
    private string _email;
    public string Email
    {
        get => _email;
        set => SetProperty(ref _email, value);
    }
}

NOTE If you were to use PropertyChanged.Fody (like the QuickStart Templates) you could simplify this to (you do not need to use BindableBase, any base class implementing INotifyPropertyChanged, or even just adding the interface to the class will work):

public class Person : BindableBase
{
    public string Email { get; set; }
}

Next you need to have your ViewModel setup to accept the parameters that you want to pass. Note that with Prism 6.3 you have a couple of options.

Starting in Prism 6.3, INavigationAware became the combination of two new navigation interfaces, INavigatingAware and INavigatedAware. As the names suggest INavigatingAware handles Navigation that is about to occur (before the view is ever pushed onto the Navigation Stack), while INavigatedAware handles Navigation that has just occurred. The result is that if you update your Model using INavigatingAware.OnNavigatingTo when the View is pushed onto the stack it would display the email, while using INavigatedAware.OnNavigatedTo may result in a noticeable UI update.

Whichever of the two methods you choose for your purposes you might go about setting your Model as follows:

public class ViewAViewModel : BindableBase, INavigatingAware
{
    // This assumes you are using PropertyChanged.Fody as mentioned above
    public Person Model { get; set; }

    public void OnNavigatingTo(NavigationParameters parameters)
    {
        // Method 1:
        Model = parameters.GetValue<Person>("Model");

        // Method 2:
        if(parameters.TryGetValue<Person>("Model", out Model))
        {
            // do something
        }

        // Method 3:
        Model = new Person
        {
            Email = parameters.GetValue<string>("email");
        };
    }
}

NOTE I should note here that having a key of Model with the ViewModel's property also being named Model is not important. It could be foobar and still work. What is important is that the key match like shown below:

_navigationService.NavigateAsync("ViewA", new NavigationParameters
{
    { "foo", new Person { Email = "[email protected]" } }
});

Model = parameters.GetValue<Person>("foo");

Finally would need to make sure that you are Binding not to the object type but rather the Property Name... Your View's Binding Context (your ViewModel) references the Person model using the property name Model so your XAML would then look like this:

<Entry Text="{Binding Model.Email}" />

Upvotes: 1

Related Questions