Access properties from one view model in another
Asked Answered
A

2

2

My WPF application follows the MVVM pattern. There are three views:

  • MainWindow
    • LoginView
    • ProjectsView

LoginView and ProjectsView are user controls imported by the MainWindow. Both views have their view model assigned. LoginViewModel defines a property ProjectList which is set by calling a webservice. Now LoginViewModel needs access to the ProjectList property and others.

I am aware that one solution might be a redesign so that there is only one view and one view model. I would do that as a backup solution but I would favor not to do so.

How should this be done? Should I use some kind of EventAggregator like in Prism? Or are there other ways to do this?

Adolfoadolph answered 16/1, 2013 at 11:13 Comment(3)
Can you explain what type of access you need from ChildVM 1 to ChildVM2 ? Is it to modify? or Is it to read?Yakutsk
@ryadavilli For the above example I only need read access, i.e. ProjectViewModel shall read ProjectList from LoginViewModel. However it might occur that something similar needs read and write access during further development.Adolfoadolph
I think theres a typo in the question, in this paragraph: "LoginView and ProjectsView are user controls imported by the MainWindow. Both views have their view model assigned. LoginViewModel defines a property ProjectList which is set by calling a webservice. Now LoginViewModel needs access to the ProjectList property and others."Keyes
K
3

So if i understood clearly, ProjectList property should be accessed from both 'LoginViewModel' and 'ProjectsViewModel'. I'd try to implement it in the 'MainViewModel' so child viewmodels can access it in a natural way.

An IEventAggregator is like a box in which you can add events, or find and subscribe to one, so i would say it's not what you need. Anyway, you could register your custom interface (box type) in the UnitySingleton.Container, which would expose ProjectList for it to be accessible everywhere. This approach makes a lot of sense when modules, which are separate assemblies, need to communicate whith each other. If this is overkill or not in your case is something you should decide, i'd personally go with the 'put it in the mainviewmodel' option.

-- Sample -- (not tested)

public class MainViewModel : ViewModelBase
{
    public MainViewModel()
    {
        LoginVM = new LoginViewModel(this);
        ProjectsVM = new ProjectsViewModel(this);
        RetrieveProjectList();
    }

    public LoginViewModel LoginVM { get; private set; }

    public ProjectsViewModel ProjectsVM { get; private set; }

    public object ProjectList { get; private set; }

    private void RetrieveProjectList()
    {
        ProjectList = ....
    }
}

It's pretty simple as you see, LoginVM and ProjectsVM will hold a reference to the MainViewModel that created them, therefore giving them access to ProjectList.

Keyes answered 16/1, 2013 at 12:50 Comment(4)
Thanks for the sample. I get the idea. However I'm still unsure when it comes to data binding in the view (XAML). That means I would set the MainViewModel as DataContext? How can I then access the properties from LoginViewModel for example?Adolfoadolph
Your MainWindow's DataContext is the MainViewModel of course! then you can bind each view inside MainWindow to the corresponding property in the MainViewModel. All perfectly wired up!Keyes
What does the reference to this mean in LoginVM = new LoginViewModel(this);? How do I need to write the constructor for those classes? public LoginViewModel(MainViewModel mainVM)?Adolfoadolph
Yes to both questions, you can then access general properties or commands defined in the mainVM. Abother advantage with this approach is when you are not sure if Mainviewmodel is going to be a singleton (specs may vary).Keyes
D
2

How should this be done? Should I use some kind of EventAggregator like in Prism? Or are there other ways to do this?

Here are a few ideas:

  • You can create a view-model class that both view-models inherit from. This base class will contain the shared properties.
  • Create a static class that contains the shared properties.
  • Using dependency injection, create a class that contains the properties, register it as a singleton in your container and inject it into your view-model's ctors.

Also, I believe that the EventAggregator is best suited for communicating between modules/assemblies. In your example, it seems like everything is in the same assembly.

Dineric answered 16/1, 2013 at 15:40 Comment(1)
Be careful with the first idea, subclassing will give you a different instance of the property for each viewmodel. That's not what he wants.Keyes

© 2022 - 2024 — McMap. All rights reserved.