1

I am developing a composite WPF application using PRISM. I have a window which has a parent UserControl. This parent usercontrol has many child Regions defined. child views exports themselves using MEF's "REGIONEXPORT" attribute. Each child view imports/creates its own viewmodel. The parent usercontrol has "OK" and "Cancel" button. On pressing "OK" i want to validate and save all childviewmodels. If any validation fails then the parent usercontrol's viewmodel needs to know. To achieve this I am using a composite command and setting it in RegionContext. Each child viewmodel gets that composite command through region context and Hope you understand that basically i need to share data between parent and child viewmodels. So I need to get the RegionContext in the child viewmodel for that I am importing the RegionManager in the viewmodel's constructor (using importing construtor,) from RegionManager i get the region context and then the commands.

public class FooViewModel
{
     [ImportingConstructor]
     public FooViewModel(IRegionManager regionManager)
     {
        var regionContext = regionManager.RegionContext;
     }
}
  1. Is it a good practive to have region manager in viewmodel??
  2. Doesn't this break MVVM? we have view related stuff's in viewmodels
  3. Is there any better approach to share data between viewmodels (other than event aggregators)
Sivasubramanian
  • 935
  • 7
  • 22

1 Answers1

2

Getting a reference to the Region Manager via the constructor of a view model is not unusual. It is the preferred method to get it. I do it this way all the time when I need to use the Region Manager for navigation.

This approach does not break MVVM. Although, I am not sure what you plan on doing with the RegionContext itself.

Another way to pass data from one VM to another is via NavigationParameters and the Region Managers RequestNavigate function. An example is below.

private readonly IRegionManager _regionManager;

public YourViewModel(IRegionManager regionManager)
{
    _regionManager = regionManager;
}

Private void DoNavigation()
{
    var parameters = new NavigationParameters();
    parameters.Add("Key", <a value or an object to pass>);
    _regionManager.RequestNavigate(“ContentRegion”, “YourViewName”, parameters);
}

You can check the parameters collection for values in the OnNavigatedTo method of the receiving VM.

public override void OnNavigatedTo(NavigationContext navigationContext)
{
    var paramKey = navigationContext.Parameters.Where(item => item.Key == "Key").FirstOrDefault();

    if (paramKey.Value != null)
    {
        // Do something…
    }    
}

You need to implement INavigationAware to get OnNavigatedTo to work.

EDIT:

If you want your data sharing to be more loosely coupled that talking to another view model via the Region Context, and you don’t want to use the Event Aggregator, then a shared service may be another way to go.

With a share service, some or all of the view models can have a reference to it, and when a property changes in the service, any object that has a reference to it can act. This share service can implement the BindableBase that comes with Prism and therefore notify when changes occur. Register the share service with whatever container you are using, get it in the ctor of the view model, reference the properties as is appropriate.

Shared Service Example

Community
  • 1
  • 1
R. Richards
  • 24,603
  • 10
  • 64
  • 64
  • Thanks Richard. :) But still i am confused. This RegionManager contains the regions and views and accessing the regionmanager(view related stuff) in the viewmodel, I feel it contradicts with MVVM. – Sivasubramanian Feb 24 '17 at 14:37
  • Noone forces you to navigate view-first, although the `ViewModelLocator` makes it clean and easy. You can also navigate view model-first, then the regions contain your view models. – Haukinger Feb 24 '17 at 14:48
  • Hi @Haukinger, There is no navigation in my requirement. I have a parent view and child view, Both view doesn't have any direct reference. Parent view creates its vm, child view creates its vm. now I need to share data between parent and child vm. For that i am using RegionContext. – Sivasubramanian Feb 26 '17 at 14:31
  • @Sivasubramanian Do you have an issue with the event aggregator? Why not use that if you don't like using the `RegionContext` approach? – R. Richards Feb 26 '17 at 14:47
  • @Sivasubramanian, in that case just have a service accessible to both view models that supplies both of them with data. – Haukinger Feb 26 '17 at 15:25
  • @Sivasubramanian I have updated the answer with an addition option (shared service), and a pointer to an example that Haukinger has posted in the past. – R. Richards Feb 26 '17 at 15:34
  • @Richards: I am fine with event aggregator but my team members doesn't want that approach because of existing too many pub sub events in other modules.(Funny right :) ) I personally feel event aggreagators are better in this scenario. Instead of having scoped region managers imported in the constructor. Also if anywhere i need to instantiate a FooViewModel then i will be doing this "new FooViewModel(null); – Sivasubramanian Feb 27 '17 at 06:46
  • @Haukinger : Thanks for your support. Having a service is a good approach but it doesn't work with my requirement. That approach i already tried, the service has to be singleton. correct me if i am wrong. if the service is singleton and what if i need to show Two parent view and two child view (basically two modeless window) at the same time?? The shared data in my case is a composite command. when both the windows are up then first window will start responding to the second window's which is not acceptable with respect to my requirement. – Sivasubramanian Feb 27 '17 at 06:57
  • @R.Richards: Thanks for your support. I will use RegionManager approach. – Sivasubramanian Feb 27 '17 at 06:59