OnNavigatedTo getting invoked twice when DataContext of View is itself

Topics: Prism v4 - WPF 4
Aug 29, 2012 at 9:40 PM
Edited Aug 29, 2012 at 10:10 PM

Hi,

I have started a project for converting a legacy C#/WPF code to PRISM/MEF. My biggest limitation is I cannot use MVVM pattern in order to re-use existing code as much as possible. 

What would be the recommendations in this scenario in terms of using best practices while still using old code. Can MVP pattern be a better choice in my scenario?

Currently I am running into a problem and seeking a solution for that as well. I have a UserControlBase class that defines the common properties and methods. Each of my view drived from UserControlBase is a usercontrol and would be displayed in tabs. The DataContext of each view is set to itself. In my TabRegionAdapter I am setting the view to the content of tabcontrol.

UserControlBase implements INavigationAware interface. Any parameters passed to the view are used to initialize the View in OnNavigatedTo function.

So for example View has TabHeader property which is initialized in OnNavigatedTo funciton. In my TabRegionAdapter I want to bind TabHeader property of view to the Header of TabControl.

To do that I was doing something like this:

TabControl newTab = new TabControl {  Content = myView, DataContext = myView.DataContext};

and then I was binding my view's TabHeader to Header of TabControl. 

It works but the problem is, due to setting DataContext of my View to itsself (which I am doing in constructor of My View like this.DataContext= this;), IsNavigationTarget and OnNavigatedTo are called two times when doing RequestNavigation meaning initialization happens two times.

I'll appreciate any help to solve this problem.

Thanks,

Imad.

Developer
Aug 30, 2012 at 2:58 PM

Hi Imad,

Regarding the behavior your are experiencing, I believe you could check the following threads where a possible approach to avoid this kind of problems have been discussed:

On the other hand take into account that the Prism Library itself is intended to be neutral with respect of the choice of the presentation pattern. In my opinion this choice will depend mostly on your application’s needs and your comfort using each of them.

Regarding this, I believe you could find the following article interesting, which contains information about the use of the MVVM pattern and also compares it with the MVP:

I hope you find this helpful,

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

Aug 30, 2012 at 5:29 PM
Edited Aug 30, 2012 at 8:11 PM

Hi AAdami,

Thanks for your reply and suggestions.

I tried that but didn't work. I need to set DataContext of TabContent to the view or to the DataContext of view and thats what is causing  OnNavigatedTo to getting called twice. I need to set dataContext of TabControl to my View since binding is the only choice of setting value of properties from view to TabControl which become available after initialization (in OnNavigatedTo). So even in my View if I set the DataContext of root child to View I still need to set DataContect of TabControl to view which causes the problem.

TabControl newTab = new TabControl { Content = myView, DataContext = myView};

So code in my adpter to set my view to content of tabcontrol executes first then I do my bindings and then OnNavigatedTo executes (in which values of view's properties are initialized). And due to setting DataContext of tab to my view in adapter, OnNavigatedTo executes twice.

Any ideas how to solve this?

Thanks,

Imad.

PS: initially thought that solution propsed above would solve my problem but then edited my initial response as it didn't solve.

Aug 30, 2012 at 9:22 PM
Edited Aug 31, 2012 at 2:08 PM

Now I tried binding TabControl properties to my view without using datacontext. This is what I did:

 TabControl newTab = new TabControl { Content = myView};

var headerBinding = new Binding("TabHeader");
headerBinding.Source = newContentPane.Content;
newContentPane.SetBinding(ContentPane.HeaderProperty, headerBinding);

Now it doesn't invoke OnNavigatedTo twice but now in case when IsNavigationTarget returns true meaning it should not navigate to view, it still calls OnNavigatedTo (meaning it stil executes initialization code) which it should not do in this case.

Will appreciate any help to solve this.

Thanks,

Imad.

 

Developer
Aug 31, 2012 at 6:18 PM
Edited Aug 31, 2012 at 6:39 PM

Hi Imad,

In my opinion, another work around to avoid this behavior, when setting this.DataContext= this; could be by providing a custom implementation of the RegionNavigationService which filters the calls to these methods. For example you could achieve this by modifying the InvokeOnNavigationAwareElement method of your RegionNavigationService class like this:

(...)
private static void InvokeOnNavigationAwareElement(object item, Action<INavigationAware> invocation)
        {
            var navigationAwareItem = item as INavigationAware;
            if (navigationAwareItem != null)
            {
                invocation(navigationAwareItem);
            }

            FrameworkElement frameworkElement = item as FrameworkElement;
            if (frameworkElement != null)
            {
                INavigationAware navigationAwareDataContext = frameworkElement.DataContext as INavigationAware;
               
            //by adding this condition: frameworkElement!=frameworkElement.DataContext the second invocation is avoided
  if (navigationAwareDataContext != null && frameworkElement!=frameworkElement.DataContext) { invocation(navigationAwareDataContext); } } } (...)

So far, I tested this approach without problems. In my case I added these modifications to a custom implementation of the RegionNavigationService and replaced the default implemetantion by registering it to the container through the IRegionNavigationService interface, this way you don't have to modify the Prism library. You could find more information on how to a replace the default Prism Types in the following section of the documentation:

Regards,

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

Sep 4, 2012 at 3:29 PM
Edited Sep 4, 2012 at 3:34 PM

Hi AAdami,

Thank you for your reply. Its a good suggestion. Will give it a try. I have also created a work item for this issue under issue tracker section.

Thanks,

Imad.