How to call functions in a main view model from other view models?
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
.
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, aWindow
code behind to the code behind of a childWindow
, or even pure data relationships without any UI involved. You can find out more about usingdelegate
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 delegate
s (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
.
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();
}
}