How to call functions in a main view model from other view models?
Asked Answered
H

2

10

My program is composed of a TreeView and two contentPresenters at ground level. The mainWindow, TreeView, and each contentPresenter all have their own viewModels.

I would like to call a function in the mainWindowViewModel from the TreeViewViewModel.

I need to do this because the mainWindowViewModel controls what is displayed in the contentPresenters, and I would like to manually update the display.

I'm guessing I would do something like this...

TreeViewViewModel:

public class TreeViewViewModel
{
     //Do I need to declare the MainWindowVM?

     public TreeViewViewModel() { ... }

     private void function()
     {
          //Command that affects display

          //Manually call function in MainWindowVM to refresh View
     }
}

I have tried to get access to the MainWindowVM from the TreeViewViewModel by using:

public MainWindowViewModel ViewModel { get { return DataContext as MainWindowViewModel; } }

But it doesn't make much sense. because the MWVM is not the DataContext of the TreeViewViewModel.

Hobie answered 22/10, 2013 at 15:32 Comment(0)
M
11

The delegate method used in this and the linked answer can be used in any parent-child relationship and in either direction. That includes from a child view model to a parent view model, a Window code behind to the code behind of a child Window, or even pure data relationships without any UI involved. You can find out more about using delegate objects from the Delegates (C# Programming Guide) page on MSDN.

I just answered a similar question to this earlier today. If you take a look at the Passing parameters between viewmodels post, you'll see that the answer involves using delegate objects. You can simply replace these delegates (from the answer) with your method(s) and it will work in the same way.

Please let me know if you have any questions.


UPDATE >>>

Yes, sorry I completely forgot you wanted to call methods instead... I've been working on too many posts tonight. So still using the example from the other post, just call your method in the ParameterViewModel_OnParameterChange handler:

public void ParameterViewModel_OnParameterChange(string parameter)
{
    // Call your method here
}

Think of the delegate as being your path back to the parent view model... it's like raising an event called ReadyForYouToCallMethodNow. In fact, you don't even need to have an input parameter. You could define your delegate like this:

public delegate void ReadyForUpdate();

public ReadyForUpdate OnReadyForUpdate { get; set; }

Then in the parent view model (after attaching the handler like in the other example):

public void ChildViewModel_OnReadyForUpdate()
{
    // Call your method here
    UpdateDisplay();
}

As you have multiple child view models, you could define the delegate in another class that they both have access to. Let me know if you have any more questions.


UPDATE 2 >>>

After reading your last comment again, I've just thought of a much simpler method that might achieve what you want... at least, if I understand you correctly. It is possible for you to Bind directly from your child views to your parent view model. For instance, this would allow you to Bind a Button.Command property in a child view to an ICommand property in your parent view model:

In TreeViewView:

<Button Content="Click Me" Command="{Binding DataContext.ParentCommand, 
RelativeSource={RelativeSource AncestorType={x:Type MainWindow}}}" />

This of course assumes that an instance of the parent view model in question is set as the DataContext of the MainWindow.

Meritorious answered 22/10, 2013 at 15:41 Comment(3)
The only thing about this answer that's different than what I'm doing is that mainWindowViewModel is the parent ViewModel, which is what I'm trying to call to. How does that change this solution?Hobie
Using the example from the other post, you would have a ParameterViewModel_OnParameterChange handler method in your MainWindowViewModel class. The only difference is that your update in that handler is already where you want it to be (in the parent view model), so you wouldn't need to pass that parameter to the other child view model... effectively you can use the same example but just do what you want with the value in the ParameterViewModel_OnParameterChange handler instead of passing it to the other view model.Meritorious
This seems to be about passing values to other ViewModels, and changing parameter values. I just want to call a function in mainWindowViewModel from a Command/Function in another ViewModel. The function in MWVM that I'm calling to just changes what's presented in the contentPresenter based on what's selected.Hobie
P
4

The easiest way is to pass a method as Action to the constructor of the child view model.

public class ParentViewModel
{
    ChildViewModel childViewModel;

    public ParentViewModel()
    {
        childViewModel = new ChildViewModel(ActionMethod);
    }

    private void ActionMethod()
    {
        Console.WriteLine("Parent method executed");
    }
}

public class ChildViewModel
{
    private readonly Action parentAction;

    public ChildViewModel(Action parentAction)
    {
         this.parentAction = parentAction;

         CallParentAction();
    }

    public void CallParentAction()
    {
        parentAction.Invoke();
    }
}
Prefab answered 7/6, 2018 at 8:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.