I'm relatively new to WPF and MVVM and the hardest thing I have found is how to simply switch a usercontrol or a view in an application.
In winforms, to have a control remove itself you would simple say this.Parent.Controls.Remove(this);
In WPF there is no generic Parent control, you would have to typecast it to the specific type (i.e. Grid) and then remove it.
This also seems to break the MVVM architecture. I have also tried data templates and content presenters, which work well, except for the fact that I can't change the datacontext from code, since the datacontext is always the viewmodellocator.
Are pages the acceptable way to do this in WPF now? What if I had a grid with a custom usecontrol and I wanted to switch it based on some variable in the viewModel? It seems like the simplest tasks cannot be accomplished easily in WPF.
MVVM Light toolkit is a lightweight toolkit for MVVM. This toolkit provides very basic classes for developing your application in MVVM architecture. You can download the latest MVVM Light Toolkit from here. MVVM Light Toolkit comes with 2 main DLLs. GalaSoft.MvvmLight.dll.
WPF with MVVM pattern have separated all the logic and operation on ViewModel and reduced the backend coding and UI event handling. Data binding infrastructure, data temple and resource system are the most important factors of WPF that made it a great partner for MVVM pattern and make this pattern so usable.
MVVM Done Right is Slow In a large application, you might need to loop through the data multiple times to make sure it has all recalculated correctly. If you just use the framework and let the framework deal with your sloppy code, this can make the system incredibly slow.
You would do so in your parent ViewModel.
For example, if your page (call it PageViewModel
) had two views (ViewModelA
and ViewModelB
), you would have a property on PageViewModel
called CurrentView
, and this would determine which View is visible. When PageViewModel.CurrentView
is set to an instance of ViewModelA
, then ViewA's DataTemplate is used to draw the content. When it's set to an instance of ViewModelB
, ViewB's DataTemplate is displayed.
<DataTemplate DataType="{x:Type local:PageViewModel}"> <ContentControl Content="{Binding CurrentView}" /> </DataTemplate> <DataTemplate DataType="{x:Type local:ViewModelA}"> <TextBlock Text="I'm ViewModelA" /> </DataTemplate> <DataTemplate DataType="{x:Type local:ViewModelB}"> <TextBlock Text="I'm ViewModelB" /> </DataTemplate>
It would be ideal to call the switch views command from the parent view (in this case the DataTemplate for the PageViewModel
), however if you wanted to switch views from within ViewModelA/B, you can either hook up the event manually when the objects get created (CurrentView.ChangeViewCommand = this.ChangeViewCommand
) or look into a messaging system. MVVM Light has a simple Messenger
class which I found was fairly easy to use, or Prism has a more advanced EventAggregator
If you want to switch Views for the same ViewModel, I would recommend a Mode property that gets used to determine which view to use. For example:
<DataTemplate x:Key="ViewA" DataType="{x:Type local:MyViewModel}"> <TextBlock Text="I'm ViewModelA" /> </DataTemplate> <DataTemplate x:Key="ViewB" DataType="{x:Type local:MyViewModel}"> <TextBlock Text="I'm ViewModelB" /> </DataTemplate> <DataTemplate DataType="{x:Type local:MyViewModel}"> <ContentControl Content="{Binding }"> <ContentControl.Style> <Style TargetType="{x:Type ContentControl}"> <Setter Property="ContentTemplate" Value="{StaticResource ViewA}" /> <Style.Triggers> <DataTrigger Binding="{Binding Mode}" Value="2"> <Setter Property="ContentTemplate" Value="{StaticResource ViewB}" /> </DataTrigger> </Style.Triggers> </Style> </ContentControl.Style> </ContentControl> </DataTemplate>
EDIT
I actually see this kind of question come up a lot, so posted something about it here if anyone is interested
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With