1

A couple of days ago I asked this question, but tbh the answers have confused me even more. So I'll ask a simpler question:

(I'm using Caliburn.Micro, this is a WPF app). Suppose you have a MainView/MainViewModel which has as children AView/AViewModel and BView/BViewModel. Your MainView is a grid, and one of the cells you want to populate with either AView or BView, depending on user choices. If I only wanted to show AView, I'd do the following:

In MainView:

<StackPanel Name="SP_Controls" VerticalAlignment="Bottom" Grid.Row="1" Grid.Column="0">
    <ContentControl Name="ViewModelToShow" Margin="10" />
</StackPanel> 

and in the MainViewModel:

public AViewModel ViewModelToShow{get; set;}

My naive Idea now would be to do something like this:

private AViewModel _AVM;
private BViewModel _BVM;

public ... ViewModelToShow{ get; set;}

and then in the code, e.g., set the viewmodel to show:

ViewModelToShow = _BVM; 

My only problem are the "...", since each ViewModel is of a different class. Is there a way to do this with generics, or should I define a base class for my ViewModels to which I cast them? But if I do that, will they still be displayed properly. Thanks.

Community
  • 1
  • 1
EluciusFTW
  • 2,565
  • 6
  • 42
  • 59
  • I'm not sure I fully understand what you're trying to do. Your VM's can inherit from PropertyChangedBase or even Screen. I have some WPF/CM examples here: https://bitbucket.org/dbeattie – Derek Beattie Nov 02 '12 at 15:39

3 Answers3

6

You view models should inherit from PropertyChangedBase, or Screen. Screen inherits from PropertyChangedBase, and also implements IScreen. Screen adds life cycle (i.e. OnActivate etc).

You could then either use your approach, i.e. have a public property called e.g. CurrentViewModel which is of type IScreen. You can then set it to the appropriate view model when needed. Note that this CurrentViewModel property should call NotifyOfPropertyChange in the setter when the reference changes, if you want the UI to be updated correctly.

Alternatively, you could think of the parent view model as a conductor for the two child view models, and use the built in Caliburn.Micro Conductor type. For example, derive from Conductor<IScreen>.Collection.OneActive.

You can then add the 2 child view models to the parent's Items collection, and call the ActivateItem method to set the current view model. Then update your view's ContentControl to have an x:Name of ActiveItem.

See here for more information.

Soonts
  • 20,079
  • 9
  • 57
  • 130
devdigital
  • 34,151
  • 9
  • 98
  • 120
1

All the above answers are correct. In terms of how view location works, the property type does not matter. Only the runtime type of the instance matters. So, you could even define the property to be of type object and it would still work. Just make sure that your property raises change notifications. In the case of a Conductor, the ActiveItem handles that for you.

EisenbergEffect
  • 3,989
  • 22
  • 26
  • Thx, this was what I was wondering... and before reading your comment I tested it with a base class, etc., finally going all the way to Object and it still worked. Very nice. – EluciusFTW Nov 05 '12 at 14:16
1

I normally inherit from a ViewModelBase class. Its a class that contains all the property changed bits and bobs. But since the DataContext property on views is just an object, the type doesn't matter too much.

Alex Curtis
  • 5,659
  • 3
  • 28
  • 31