Execute UserControl readonly ICommand from ViewModel - c#

I have a specialized UserControl to play media content called PlayerView.
The control has its own commands (readonly, not provided by client).
public partial class PlayerView
{
public PlayerView()
{
InitializeComponent();
PlayCommand = new RelayCommand(() =>
{
// Play some media: audio/video.
});
}
...
#region PlayCommand property
private static readonly DependencyPropertyKey PlayCommandPropertyKey = DependencyProperty.RegisterReadOnly(
"PlayCommand",
typeof(ICommand),
typeof(PlayerView),
new PropertyMetadata());
public static readonly DependencyProperty PlayCommandProperty = PlayCommandPropertyKey.DependencyProperty;
public ICommand PlayCommand
{
get { return (ICommand)GetValue(PlayCommandProperty); }
private set { SetValue(PlayCommandPropertyKey, value); }
}
#endregion
...
}
The play command of the control works fine from XAML:
<Controls:PlayerView x:Name="PlayerView" />
<Button Command="{Binding ElementName=PlayerView, Path=PlayCommand, Mode=OneWay}" Content="Play" />
But currently, I am implemeting slideshow feature and I would like to execute the play command of the control from the ViewModel.
public class SlideshowViewModel : ViewModelBase
{
// Stores collection of audio/video clips to be played by the PlayerView.
// Assume that this ViewModel should invoke PlayerView PlayCommand.
}
public class MainViewModel : ViewModelBase
{
// Stores a lot of stuff.
public SlideshowViewModel Slideshow { get; }
}
The question is: how the SlideshowViewModel can execute the PlayCommand of this control? Is there a best practice?

If I am understanding your issue correctly, the ViewModel should contain the implementation of the Command, not the View. This would be a truer MVVM implementation, and then the VM can call that command from within itself, if necessary.
edit:
to answer your question,
public partial class PlayerView : IHaveAPlayCommand
{
public PlayerView()
{
this.DataContext = new ViewModel(this);
}
}
public class ViewModel
{
IHaveAPlayCommand view;
public ViewModel(IHaveAPlayCommand view)
{
this.view = view
}
}

Related

How to provide Command-Property for custom control in MVVM (.NET MAUI)

I'm trying to build a custom control in .NET MAUI, that should provide an BindableProperty of ICommand for its parent. Here is a basic example for what i try to achieve.
MainPage View (MainPage.xaml)
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:views="clr-namespace:SampleApp.Views"
x:Class="SampleApp.MainPage">
<views:MyCustomControl DoSomething="{Binding DoSomethingCommand}"></views:MyCustomControl>
</ContentPage>
MainPage View Class (MainPage.xaml.cs)
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
BindingContext = new MainPageViewModel();
}
}
MainPage View Model (MainPageViewModel.cs)
public class MainPageViewModel : ObservableObject
{
public ICommand ProcessNewScoreCommand { get; }
public MainPageViewModel()
{
ProcessNewScoreCommand = new Command(DoSomething);
}
private void DoSomething()
{
// Do something
}
}
MyCustomControl View Class (MyCustomControl.xaml.cs)
public partial class MyCustomControl : ContentView
{
public static readonly BindableProperty DoSomethingProperty =
BindableProperty.Create(nameof(DoSomething), typeof(ICommand), typeof(MyCustomControl));
public ICommand DoSomething
{
get => (ICommand)GetValue(DoSomethingProperty);
set => SetValue(DoSomethingProperty, value);
}
public MyCustomControl()
{
InitializeComponent();
BindingContext = new MyCustomControlViewModel(DoSomething);
}
}
MyCustomControl View-Model (MyCustomControlViewModel.cs)
public class MyCustomControlViewModel : ObservableObject
{
public ICommand DoSomething { get; }
public MyCustomControlViewModel(ICommand doSomethingCommand)
{
DoSomething = doSomethingCommand;
}
private void PerformSomeLogic()
{
// Any calulations/logic
// ...
if (DoSomething.CanExecute(null))
{
// Execute command, so that parent component gets informed and can act.
DoSomething.Execute(null);
}
}
}
While debugging, the Property DoSomething of class MyCustomControl.xaml.cs is always null. Also it seems, that its setter isn't called at any time. What am I doing wrong?
The reason it's not working is that you are creating a VM for your custom control i.e. the view then assigning it a context and then later on in your custom control you are changing its BindingContext all over again, Custom Controls should not have their own predefined BindingContext.
Steps to fix this:
Remove your MyCustomControlViewModel class.
Now your CustomControl.xaml.cs would look like this:
public partial class MyCustomControl : ContentView
{
public static readonly BindableProperty DoSomethingProperty =
BindableProperty.Create(nameof(DoSomething), typeof(ICommand), typeof(MyCustomControl));
public ICommand DoSomething
{
get => (ICommand)GetValue(DoSomethingProperty);
set => SetValue(DoSomethingProperty, value);
}
public MyCustomControl()
{
InitializeComponent();
}
}
Now your View's VM should be the one that handles the logic so you don't have multiple BindingContext's confusing and the compiler(By searching it in the wrong place):
public class MainPageViewModel : ObservableObject
{
public ICommand DoSomething { get; }
public MainPageViewModel()
{
DoSomething = new Command(DoSomething);
}
Good luck, let me know if there is some other questions you have.
A basic guide to MVVM with XF and MAUI: https://learn.microsoft.com/en-us/xamarin/xamarin-forms/xaml/xaml-basics/data-bindings-to-mvvm

Change ViewModel from Service WPF

I am learning to create a WPF application following the MVVM patern. I'm try change data in viewmodel from service class but it can work, here is example code:
In MainWindow.xaml:
<Grid Grid.Row="6">
<TextBox materialDesign:HintAssist.Hint="Status"
Text="{Binding Status, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
Style="{StaticResource MaterialDesignFloatingHintTextBox}"
VerticalAlignment="Center" />
</Grid>
In MainViewModel.cs:
public class MainViewModel : BaseViewModel
{
private static MainViewModel _instance = new MainViewModel();
public static MainViewModel Instance { get { return _instance; } }
//...
// Status
private string _Status = "Status";
public string Status { get => _Status; set { _Status = value; OnPropertyChanged(); } }
public MainViewModel()
{
////
// => This command can change status
// Start
StartCommand = new RelayCommand<object>((p) => { return true; }, (p) =>
{
OutStatus("Task success!");
});
}
public void OutStatus(string status)
{
Status = status;
}
}
In UtilitiesService.cs
public static class UtilitiesService{
public static void SetStatus(){
// => Here i can't change Status and can't binding to MainWindow.xaml
MainViewModel.Instance.OutStatus("Change Status in service");
}
}
So how can I change a property in manviewmodel in service file.Sorry Im so noob :))
You are using different instances of MainViewModel for data binding and for updating.
Also don't use public static instances or members across the application. Instead directly pass around the instance (in your case MainViewModel and UtilitiesService).
Generally static class members like properties or fields introduce a potential memory leak, because the garbage collector can't collect them to free memory. It also makes unit testing difficult and defies the concept of object oriented language key features like encapsulation. It will make code hard to modify.
In the simplest scenario, you can create the MainViewModel instance in your MainWindow. You can also create a shared instance of UtilitiesService at this point as well.
It's unclear what purpose UtilitiesService has. If it is meant to update MainViewModel by other View Model classes you can do it your way. If it is meant to be used in the Model, then you shouldn't do it your way. In this case your MainVoewModel would listen to the UtilitiesService events to update itself. Because in MVVM the Model does never talk to the View Model.
The recommended C# naming convention suggests to name fields using the camelCase pattern (starting with a lower case letter). Microsoft Docs: Naming Guidelines
A TextBox.Text binding that is configured to bind OneWay is pretty useless. In this case the TextBox only serves as display. You should then use TextBlock instead.
MainViewModel.cs
public class MainViewModel : BaseViewModel
{
//...
// Status
private string _status = "Status";
public string Status { get => _status; set { _status = value; OnPropertyChanged(); } }
public MainViewModel()
{
////
// => This command can change status
// Start
StartCommand = new RelayCommand<object>((p) => { return true; }, (p) =>
{
SetStatus("Task success!");
});
}
public void SetStatus(string status)
{
Status = status;
}
}
UtilitiesService.cs
public class UtilitiesService
{
private MainViewModel MainViewModel { get; }
public void UtilitiesService(MainViewModel mainViewModel)
{
this.MainViewModel = mainViewModel;
}
public void SetStatus()
{
// Change MainViewModel.Status and update bindings in MainWindow.xaml
this.MainViewModel.SetStatus("Change Status in service");
}
}
MainWindow.xaml.cs
partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var mainViewModel = new MainViewModel();
this.DataContext = mainViewModel;
var sharedUtilitiesService = new UtilitiesService(mainViewModel);
// Pass the shared UtilitiesService instance to other view model classes
// to allow them to update the MainViewModel anonymously.
var otherViewModel = new OtherViewModel(sharedUtilitiesService);
}
}
MainWindow.xaml
<Window>
<TextBlock Text="{Binding Status}" />
</Window>

Xamarin Forms watch ViewModel property from .xaml.cs class

As the title suggests, on Xamarin Forms, I am trying to watch from a View when a property on the ViewModel changes.
This is my ViewModel class
public class RegisterViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public bool AutomaticVerificationDone { get; set; }
public ICommand AutomaticVerification
{
get
{
return new Command(async () =>
{
AutomaticVerificationDone = true;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("AutomaticVerificationDone"));
});
}
}
}
This is my Register.xaml.cs class
public partial class Register : ContentPage
{
public static readonly BindableProperty AutomaticVerificationDoneProperty = BindableProperty.Create(nameof(AutomaticVerificationDone), typeof(bool), typeof(Register), false);
public bool AutomaticVerificationDone
{
get { return (bool)GetValue(AutomaticVerificationDoneProperty); }
set
{
SetValue(AutomaticVerificationDoneProperty, value);
if (value)
accessButton.Opacity = 1;
else
accessButton.Opacity = 0.8f;
}
}
public Register()
{
InitializeComponent();
NavigationPage.SetHasNavigationBar(this, false);
this.BindingContext = new RegisterViewModel();
}
}
Doing in this way nothing happens.
What am I missing?
Bindable properties don't use your setter; they go directly through the bindable property system.
Instead, you need to pass a propertyChanged callback to BindableProperty.Create.
But actually, you should bind Opacity in your XAML (using a converter) instead.

Interact between Model and ViewModel of different UserControls without violating MVVM

EDIT: Added concrete example to clarify what I trying to achieve.
Here is application scheme:
To make code simpler, I will use trivial Messenger class instead of event aggregator from Prism. Tuple contains Id and string payload.
public static class Messenger
{
public static event EventHandler<Tuple<int, string>> DoWork;
public static void RaiseDoWork(int id, string path)
{
DoWork?.Invoke(null, new Tuple<int, string>(id, path));
}
}
Model instance subscribe to messenger for knowing when to start work (if Id correct), and notify view-model when work finished.
public class Model
{
public int id;
public Model(int id)
{
this.id = id;
Messenger.DoWork += (sender, tuple) =>
{
if (tuple.Item1 != this.Id)
{
return;
}
var result = tuple.Item2 + " processed with id " + this.id;
this.OnWorkCompleted(result);
};
}
public event EventHandler<string> WorkCompleted;
private void OnWorkCompleted(string path)
{
this.WorkCompleted?.Invoke(null, path);
}
}
UserControlResult is responsible for payload processing and result output. To make code simpler, lets just trace output instead of putting it on UI. So XAML will be default.
Code-behind:
public partial class UserControlResult : UserControl
{
private ResultViewModel viewModel;
public UserControlResult()
{
this.InitializeComponent();
}
public void Init(int id)
{
this.viewModel = new ResultViewModel(id);
this.DataContext = this.viewModel;
}
}
View-model:
public class ResultViewModel
{
private Model model;
public ResultViewModel(int id)
{
this.model = new Model(id);
this.model.WorkCompleted += path =>
{
Trace.WriteLine(path);
};
}
}
UserControlButtons contains buttons, one of them should start processing of model in UserControlResult via messenger. To make code simpler, lets omit command implementation and just show its handler.
Code-behind:
public partial class UserControlButtons : UserControl
{
private ButtonsViewModel viewModel;
public UserControlButtons()
{
this.InitializeComponent();
}
public void Init(int id)
{
this.viewModel = new ButtonsViewModel(id);
this.DataContext = this.viewModel;
}
}
View-model:
public class ButtonsViewModel
{
private int id;
public ButtonsViewModel(int id)
{
this.id = id;
}
// DelegateCommand implementation...
private void StartWorkingCommandHandler()
{
Messenger.RaiseDoWork(this.id, "test path");
}
}
UserControlParent contains both UserControlResult and UserControlButtons. His only role is to pass Id to them, so he doesn't even need view-model.
Xaml:
<StackPanel>
<uc:UserControlResult x:Name="UserControlResult" />
<uc:UserControlButtons x:Name="UserControlButtons" />
</StackPanel>
Code-behind:
public partial class UserControlParent : UserControl
{
public UserControlParent()
{
this.InitializeComponent();
}
public void Init(int id)
{
this.UserControlResult.Init(id);
this.UserControlButtons.Init(id);
}
}
And finally MainWindow contains two instances of UserControlParent. Its role to assign them different Ids.
Xaml:
<StackPanel>
<uc:UserControlParent x:Name="UserControlParent1" />
<uc:UserControlParent x:Name="UserControlParent2" />
</StackPanel>
Code-behind:
public partial class MainWindow : Window
{
public MainWindow()
{
this.InitializeComponent();
this.UserControlParent1.Init(111);
this.UserControlParent2.Init(222);
}
}
This will work: pressing button in UserControlButtons will start working in UserControlResult model, and both UserControlParent will working correct and independend thanks to Id.
But I believe that this chain of invoking Init methods is violates MVVM because code-behind (which is View in MVVM) should not know anything about Id value (which is relative to Model in MVVM). Talking that, I'm sure that Id is not part of view-model, because it doesn't have any presentation in UI.
How can I pass Id value from top window to "deepest" view-models without violating MVVM?
Original Question
Here is WPF application consisting from 3 UserControls:
UserControl3 is a part of UserControl2 content. I keep MVVM during developing and using Prism.
I need to invoke method of custom class (which is model in terms of MVVM) in UserControl3 from view-model of UserControl1. The restriction that custom class can't be singleton. I suppose to do it one of the following way:
Using event aggregator from Prism. UserControl1 view-model is publisher and UserControl3 model is subscriber. For this I'll need to create unique Id in Window and pass it to UserControl1 and UserControl3.
Creating service instance in Window and pass it to UserControl1 and UserControl3. Then UserControl1 will just invoke method of this instance.
Window pass UserControl2 instance to UserControl1. View-model in UserControl1 will just invoke method of UserControl2, which will invoke method of UserControl3 and so on.
It seems like 2 and 3 approaches violates MVVM. How would you resolve this situation?
I would use option 1. I use MVVM Light to send a message and whoever receives that specific message will fire off the service method. Loosely coupled.
I think I achieved truly MVVM implementation shown in simplified example below. Special thanks to Ed Plunkett's comment and Nikita's answer.
First, I don't need to pass unique Ids anymore. For identification of different ParentViewModel instances, I just pass them different Messenger instances (which replaces Prism's EventAggregator for the sake of simplicity):
internal class Messenger
{
public event EventHandler<string> DoWork;
public void RaiseDoWork(string path)
{
this.DoWork?.Invoke(this, path);
}
}
Second, it seems like in my particular case Model should not worry about Messenger's DoWork event. As soon as this event raised in one view-model (ButtonsViewModel), it is more appropriate for this event to be consumed by another view-model (ResultViewModel) rather than by Model itself. So Model simplified too:
internal class Model
{
public string Process(string input)
{
return input + " processed!";
}
}
Below demonstrated all view-models "from top to bottom".
internal class MainViewModel
{
private readonly Messenger eventAggregator1 = new Messenger();
private readonly Messenger eventAggregator2 = new Messenger();
public MainViewModel()
{
this.ParentViewModel1 = new ParentViewModel(this.eventAggregator1);
this.ParentViewModel2 = new ParentViewModel(this.eventAggregator2);
}
public ParentViewModel ParentViewModel1 { get; }
public ParentViewModel ParentViewModel2 { get; }
}
internal class ParentViewModel
{
public ParentViewModel(Messenger eventAggregator)
{
this.ButtonsViewModel = new ButtonsViewModel(eventAggregator);
this.ResultViewModel = new ResultViewModel(eventAggregator);
}
public ButtonsViewModel ButtonsViewModel { get; }
public ResultViewModel ResultViewModel { get; }
}
internal class ButtonsViewModel
{
private readonly Messenger eventAggregator;
public ButtonsViewModel(Messenger eventAggregator)
{
this.eventAggregator = eventAggregator;
this.StartCommand = new DelegateCommand(this.StartProcessing);
}
public DelegateCommand StartCommand { get; }
private void StartProcessing()
{
this.eventAggregator.RaiseDoWork("test path");
}
}
internal class ResultViewModel : ViewModelBase
{
private readonly Model model = new Model();
private string textValue;
public ResultViewModel(Messenger eventAggregator)
{
eventAggregator.DoWork += (sender, s) => this.DoWorkHandler(s);
}
public string TextValue
{
get { return this.textValue; }
set { this.SetProperty(ref this.textValue, value); }
}
private void DoWorkHandler(string s)
{
var result = this.model.Process(s);
this.TextValue = result;
}
}
Note that in ResultViewModel I replaced Trace.WriteLine with actual screen output (because now strings are without Id, so trace output the same). ViewModelBase just implements INotifyPropertyChanged.
Below demonstrated content part of all views "from top to bottom".
<!-- MainWindow.xaml -->
<StackPanel Orientation="Horizontal">
<views:UserControlParent DataContext="{Binding ParentViewModel1}" />
<views:UserControlParent DataContext="{Binding ParentViewModel2}" />
</StackPanel>
<!-- UserControlParent.xaml -->
<StackPanel>
<local:UserControlResult DataContext="{Binding ResultViewModel}" />
<local:UserControlButtons DataContext="{Binding ButtonsViewModel}" />
</StackPanel>
<!-- UserControlButtons.xaml -->
<Grid>
<Button Content="Test" Command="{Binding StartCommand}" />
</Grid>
<!-- UserControlResult.xaml -->
<Grid>
<TextBlock Text="{Binding TextValue}" />
</Grid>
And finally this two worlds are connected in App.xaml.cs:
private void App_OnStartup(object sender, StartupEventArgs e)
{
new MainWindow { DataContext = new MainViewModel() }.Show();
}
Seems like MVVM, but any remarks are welcome.

How to provide ChildViewModel with data from MainViewModel

Often when I’m designing an MVVM application, the following scenario comes up. A Window, having multiple children, sharing the same data source.
I’m trying to decide on the best way to implement a single datasource for all children. There are 3 options I can think of, all with their own advantages and disadvantages.
Example
The Window has two child UserControls, each in their own tab.
UI is linked up like this.
In order to keep modularity and provide them with data, the same design is reflected in ViewModels.
The MainViewModel is set up like this.
public class MainViewModel : ViewModelBase
{
private readonly ChildViewModelA _childViewModelA = new ChildViewModelA();
private readonly ChildViewModelB _childViewModelB = new ChildViewModelB();
public ChildViewModelA ChildViewModelA { get { return this._childViewModelA; } }
public ChildViewModelB ChildViewModelB { get { return this._childViewModelB; } }
}
The MainWindow instantiates the MainViewModel and sets DataContext of the children. Child controls are bound to data properties.
public partial class MainWindow : Window
{
private readonly MainViewModel _viewModel = new MainViewModel();
public MainWindow()
{
InitializeComponent();
}
public MainViewModel ViewModel { get { return this._viewModel; } }
}
<Window x:Class="WpfApplication3.View.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:WpfApplication3.View.Controls"
Title="MainWindow" Height="350" Width="525"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
<TabControl>
<TabItem Header="Tab 1">
<controls:ChildViewA DataContext="{Binding ViewModel.ChildViewModelA}"/>
</TabItem>
<TabItem Header="Tab 2">
<controls:ChildViewB DataContext="{Binding ViewModel.ChildViewModelB}"/>
</TabItem>
</TabControl>
</Grid>
</Window>
To prevent every ViewModel from retrieving the same data from the database, I want to load data in the MainViewModel and provide the children. However, there are multiple ways of doing this.
Example 1: Using a setter method on the children
public class MainViewModel : ViewModelBase
{
...
private readonly FakeDataManager _fakeDataManager = new FakeDataManager();
public MainViewModel()
{
this.CurrentPerson = _fakeDataManager.GetNextPerson();
}
private Person _currentPerson;
public Person CurrentPerson
{
get { return this._currentPerson; }
set
{
this._currentPerson = value;
this.RaisePropertyChanged("CurrentPerson");
this.ChildViewModelA.SetPerson(this.CurrentPerson);
this.ChildViewModelB.SetPerson(this.CurrentPerson);
}
}
public class ChildViewModelA : ViewModelBase
{
private Person _currentPerson;
public Person CurrentPerson
{
get { return this._currentPerson; }
set
{
this._currentPerson = value;
this.RaisePropertyChanged("CurrentPerson");
}
}
}
Easy to implement, however quickly get's hard to remain. Not a lot of code reuse. No loose coupling. Should not use this.
Example 2: Putting data in a container
public class MainViewDataContainer : INotifyPropertyChanged
{
private Person _currentPerson;
public Person CurrentPerson
{
get { return this._currentPerson; }
set
{
this._currentPerson = value;
this.RaisePropertyChanged("CurrentPerson");
}
}
}
public class MainViewModel : ViewModelBase
{
...
private readonly FakeDataManager _fakeDataManager = new FakeDataManager();
private readonly MainViewDataContainer _dataContainer = new MainViewDataContainer();
public MainViewModel()
{
this._childViewModelA = new ChildViewModelA(_dataContainer);
this._childViewModelB = new ChildViewModelB(_dataContainer);
this._dataContainer.CurrentPerson = _fakeDataManager.GetNextPerson();
}
public class ChildViewModelA : ViewModelBase
{
private readonly MainViewDataContainer _dataContainer;
public ChildViewModelA(MainViewDataContainer dataContainer)
{
this._dataContainer = dataContainer;
}
public MainViewDataContainer DataContainer { get { return this._dataContainer; } }
}
Easier to maintain, more code reuse. Looser coupling.
Example 3: Storing in MainViewModel Properties and provide to children through an interface
public interface IMainDataProvider
{
Person CurrentPerson { get; }
}
public class MainViewModel : ViewModelBase, IMainDataProvider
{
private readonly ChildViewModelA _childViewModelA;
private readonly ChildViewModelB _childViewModelB;
private readonly FakeDataManager _fakeDataManager = new FakeDataManager();
public MainViewModel()
{
this._childViewModelA = new ChildViewModelA(this);
this._childViewModelB = new ChildViewModelB(this);
this.CurrentPerson = _fakeDataManager.GetNextPerson();
}
private Person _currentPerson;
public Person CurrentPerson
{
get { return this._currentPerson; }
set
{
this._currentPerson = value;
this.RaisePropertyChanged("CurrentPerson");
}
}
}
public class ChildViewModelA : ViewModelBase
{
private readonly IMainDataProvider _dataProvider;
public ChildViewModelA(IMainDataProvider dataProvider)
{
this._dataProvider = dataProvider;
}
public IMainDataProvider DataProvider { get { return this._dataProvider; } }
}
Yet again easier to maintain, more code reuse. Loose coupling.
Example 3 seems to be the best solution, however is this true? How do you think about this? Are there better ways to solve this issue?
If CurrentPerson is used by both ChildViewModels and MainView is the one who can change the CurrentPerson. How I will proceed to solve this problem is:
Define one base VM ChildViewModelBase : ViewModelBase with CurrentPerson property (with INotifyPropertyChanged and all). All of my ChildViewModels will extend this VM.
Use Event Aggregator http://msdn.microsoft.com/en-us/library/ff921122.aspx. Using EventAggregator you can subscribe to CurrentPersonChanged event in your ChildViewModelBase.
From you MainViewModel once the CurrentPerson is loaded from db, raise CurrentPersonChanged event with new Person as event arguement.
In event handler in the ChildViewModelBase, set CurrentPerson that you get as event argument.
In this way it would not matter to your ChildViewModels who is loading the Person from DB. Today it is MainView, tommorow it can be some other View also. You will just need to raise the above event with the person object as argument and Child Views will get it.

Categories

Resources