I am building a WPF
program using the MVVM
Framework, along with Ninject
for Dependancy Injection
. I have created two projects, a .Net Class Library
Core project for use with other .Net
Applications and a WPF
specific application.
Currently I am changing pages with my application using an ApplicationViewModel
with a Property
CurrentPage
. CurrentPage
is an Enum
type called ApplicationPage
containing the different pages within my application. Within the MainWindow of my WPF application is a frame whose Content
is bound
to the CurrentPage Property
and uses a value converter to convert the value to different CustomPages
I have made using a switch
statment, like so:
if (value is ApplicationPage)
switch ((ApplicationPage)value)
{
case ApplicationPage.PageOne:
return new PageOne();
case ApplicationPage.PageTwo:
return new PageTwo();
default:
throw Exception;
}
}
I would like to use Constructor
Injection
to pass the View Models
for these pages into a Page's
Constructor
within the Converter
, Using ViewModels
that have in turn been Injected
into the ApplicationViewModel
class, kind of like so:
case ApplicationPage.PageOne:
return new PageOne(PageOneViewModel);
My first thought was, is there some way of making the CurrentPage
Property
actually a specific ViewModel
and perform a switch
on which ViewModel
so the Converter
converts a ViewModel
to a Page
?
However the Type of CurrentPage
is an issue as it has to be set to one of the ViewModels
and therefore cannot take the value of a different ViewModel
, leaving you stuck with only one ViewModel
Class
to work with.
My thoughts are: Is there a way to pass in the ViewModel
to the Converter
? Or Could I set CurrentPage
to an IViewModelFactory
and Create the ViewModel
within the converter from the Factory? In which case how would I change the value of CurrentPage
in order to change the page in the application?
Is there a way to stick to Dependency
Injection
while following this logic, or is there another way and do I need to rethink my code for page changing? Unfortunately most examples I have seen have fallen into the so called ServiceLocator
anti-pattern.
The answer is to use data templates as follows,
<Window.Resources>
<DataTemplate x:Key="View1Template" DataType="{x:Type local:MainWindowViewModel}">
<!-- Custom control style with a Data Context set to a Viewmodel
object in the MainWindowViewModel -->
<local:CustomPage1 DataContext="{Binding CustomPage1ViewModel}" />
</DataTemplate>
<DataTemplate x:Key="View2Template" DataType="{x:Type local:MainWindowViewModel}">
<!-- Custom control style with a Data Context set to a Viewmodel
object in the MainWindowViewModel -->
<local:CustomPage2 DataContext="{Binding CustomPage2ViewModel}" />
</DataTemplate>
</Window.Resources>
Then setting a Data Trigger
within the Content Control Style
;
<ContentControl Content="{Binding}">
<ContentControl.Style>
<Style TargetType="{x:Type ContentControl}">
<!-- The Default/initial View being shown -->
<Setter Property="ContentTemplate" Value="{StaticResource View1Template}" />
<!-- Triggers bound to the CurrentView Property -->
<Style.Triggers>
<DataTrigger Binding="{Binding CurrentView}" Value="1">
<Setter Property="ContentTemplate" Value="{StaticResource View1Template}" />
</DataTrigger>
<DataTrigger Binding="{Binding CurrentView}" Value="2">
<Setter Property="ContentTemplate" Value="{StaticResource View2Template}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
The CurrentView
is a property that can be changed in code to Trigger
a change in the UI
- can be set to an Enum
of PageNames
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.