My prefered approach is to have a single top level view model which you bind to everything.
ie, and i'm just going to use pseudocode, sorry WPF is too long winded
<MainWindow>
<Title>@title</Title>
<BigList Items=@items />
<Popup IsVisible=@showPopup>
<BigList Items=@newItems />
<Button OnClick=@getNewItems />
<Button OnClick=@importNewItems />
</Popup>
</MainWindow>
ICommand getNewItems()
{
this.newItems = //load items from wherever
}
ICommand importNewItems()
{
this.items.AddRange(this.newItems)
}
Your various custom controls do have their own view models, but they are purely for exposing properties, you don't have any (non view) logic in them, they are designed to be generic.
This approach keeps things simple and on a single level, it avoids event subscriptions and unsubscriptions or passing in functions.
A popular alternative is the mediator pattern.
//mainwindow
<MainWindow>
<Title>@title</Title>
<BigList Items=@items />
<Popup IsVisible=@showPopup/>
</MainWindow>
MainVM
{
OnLoad()
{
this.mediator.Listen("importItems", i => { this.items = i});
}
}
//popup usercontrol
<UserControl IsVisible=@showPopup>
<BigList Items=@items/>
<Button OnClick=@getNewItems />
<Button OnClick=@importNewItems />
</UserControl>
PopUpVM
{
ICommand getNewItems()
{
var items = //load items from wherever
this.mediator.Send("newItems", items);
}
ICommand importNewItems()
{
this.mediator.Send("importItems", items);
}
}
The benefit here is the mediator is a global object which everything can subscribe to and send events. This breaks the need to link all the different potentially unrelated controls you might have in your application. Say for example you have some side bar or menu which is at a higher level than your MainVM but has some sub component that pops up notifications "Congrats on your import!" whenever you do X or Y
Note in my first example the Popup usercontrol takes content, perhaps a more comparable version would be something like:
//popup usercontrol
<UserControl IsVisible=@showPopup>
<BigList Items=@items/>
<Button OnClick=@OnGetNewItems/>
<Button OnClick=@OnImportNewItems/>
</UserControl>
PopUp //codebehind
{
public List<Item> items
public ICommand OnGetNewItems
public ICommand OnImportNewItems
}