property getter getting called before navigation complete

Topics: Prism v4 - Silverlight 4
Mar 26, 2012 at 10:05 AM

Hi

In my viewmodel I have properties as follows:

private MyModel_DTO _myModel_DTO; 
 
public int OrderID 
{ 
 
get {return _myModel_DTO.OrderID;} 
set 
{ 
if (_myModel_DTO.OrderID != value} 
{ 
_myModel_DTO.OrderID = value; 
RaisePropertyChanged(OrderID); 
}

Also in my viewmodel I implement the INavigationAware interface. In the OnNavigatedTo method I check the passed in parameter (OrderID) and make a call to my service to fill the _myModel_DTO object.

This call to the service is using reactive extentions.

My problem is that 'get {return _myModel_DTO.OrderID;}' is being called before the method returns the data resulting in my view not displying any data as it hasn't got any yet.

The _myModel_DTO object does get filled with data eventually but this is after the 'get {return_myModel_DTO.OrderID;}' is called.

The only solution I have at the moment is to call the RaisePropertyChanged event for each property in the OnCompleted event of the rx method.

Is there a better approach to this or can anybody spot an
obvious mistake that I can't.

Thanks

Paul

p.s. I also posted this on the Silverlight forums where I was advised that what I was trying to acheive might not work and would need to change it.  Posted here hoping that others that have used the INavigationAware interface have found a workaround for this.

Mar 26, 2012 at 4:11 PM

I'm not sure this would work and don't think it is a great solution, but it might be "something is better than nothing" at this point :)

I'm thinking you can try to use a single property exposing your entire DB model.

public int MyModel_DTO
{ 
 
get {return _myModel_DTO;} 
set 
{ 
if (_myModel_DTO != value} 
{ 
_myModel_DTO = value; 
RaisePropertyChanged(MyModel_DTO); 
}

In your view you would bind to the properties of the model.

... Text = "{binding MyModel_DTO.OrderId}"...

Then you could raise the single notify property when the object is loaded.

RaisePropertyChanged(MyModel_DTO); 

I'm just not sure if raising a notify event on the object would trigger binding updates on it's properties.

Developer
Mar 26, 2012 at 5:21 PM
Edited Mar 26, 2012 at 5:30 PM

Hi Paul,

Based on my understanding of your scenario, I believe you could also try implementing the IConfirmNavigationRequest interface provided with Prism. This way you can control if the navigation request is carried out immediately or is deferred. This should allow you to retrieve the parameter passed from the navigation context and to call the service before the navigation is carried.

The IConfirmNavigationRequest interface derives from the INavigationAware interface and adds the ConfirmNavigationRequest method. The ConfirmNavigationRequest method provides two parameters, a reference to the current navigation context as described earlier, and a callback method that you can call when you want navigation to continue.

If you want to defer navigation, you can store a reference to the continuation callback that you can call when the service completes. The navigation operation will be pending until you call the continuation callback.

Take into account that this interface should be implemented in the previous view / view model in the navigated region.

If you are interested, you could find more information about this in the following chapter of the Prism documentation:

Also you could find a sample ("ConfirmationCallbackSample") which might result handy in the following thread:

I hope you find this helpful,

Agustin Adami
http://blogs.southworks.net/aadami


Mar 27, 2012 at 4:09 PM

Thanks Imcculloch, Agustin Adami.

Agustin Adami my understanding is that the ConfirmNavigationRequest and also the OnNavigatedFrom methods are called when leaving an active view, am I correct in saying this? 

In my senario I'm navigating to a view that is not currently in the region so a new view will need to be created and this does work and in this case the ConfirmNavigationRequest will not be invoked, is this correct?

When navigating to this new view in the OnNavigatedTo method I retreive the parameter(orderid) and call a method in a service to get me the details for this order.  This fills an order object as shown above.  The view is bound to public properties which in their get/set the values are pulled from the order object so to speak(example above). 

It does sound like I need to defer navigation/displaying of the view until the service comes back with the data as the public properties are not updaing in the view as the get accessor has been called before the order object has been filled with data from the service call.

Hope I'm making sence here and have not misunderstood what you are saying.

Thanks

Paul

Developer
Mar 27, 2012 at 7:18 PM
Edited Mar 27, 2012 at 7:19 PM

Hi,

As you mentioned, if you wish to defer navigation using ConfirmNavigationRequest you will need to have a previous view that implements this interface in the same region.

In my opinion, another possible approach could be to perform navigation as usual and then change the visual representation of the view depending if the data is loaded or not:

First of all, as explained in the INotifyPropertyChanged.PropertyChanged event discription on MSDN, you can raise the PropertyChange event passing an empty string (String.Empty) to indicate that all the properties in the view model have changed. Based on my understanding, by doing this you should be able to update all the properties in a single line:

// Method in the view model...
public void OnCompleted (MyModel_DTO model)
{
    this._MyModel_DTO = model;
    this.RaisePropertyChanged(String.Empty);
}

Then, if you wish the view to not being shown before the data has been retrieved for the service, a possible approach could be to notify the view that "the view model is loading data," so that the view can change its appearance to inform the user about this. For example, the view could show a TextBlock with the legend "Loading" over the other components of the view or simply hide the view changing its Visibility property. The view model could inform the view of this state through an InteractionRequest, exposing a simple property to which the view can bind or using another mechanism of your preference.

You can inform the view that the view model is loading data in the view model's OnNavigatedTo method or in its constructor, and change this state when the service returns the data:

public class MyViewModel : NotificationObject, INavigationAware
{
    [ . . . ]

    // The view would bind to this property to know
    // the "state" of the view model.
    public bool IsBusy { get; private set; }

    public void OnNavigatedTo(NavigationContext navigationContext)
    {
        this.IsBusy = true;
        this.RaisePropertyChanged("IsBusy");

        // Request of data from the service...
    }

    public void OnCompleted (MyModel_DTO model)
    {
        this._MyModel_DTO = model;
        this.IsBusy = false;
        this.RaisePropertyChanged(String.Empty);
    }

    [ . . . ]
}

In my opinion, by doing something like this you can provide feedback to the user about what the application is doing while being able to keep the abstraction between different views / view models in your application without requiring a lot of code.

I hope you find these suggestion useful,

Damian Cherubini
http://blogs.southworks.net/dcherubini

Mar 28, 2012 at 9:56 AM

Perfect Damian

RaisePropertyChanged(string.empty) worked like a charm, thank you very much.  Never knew you could do that with propertychanaged.  Also thanks to all others who replied.

Paul