I am developing a C#/WPF/MVVM/UWP app which uses a ViewModelLocator which looks like this:
public class ViewModelLocator
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance",
"CA1822:MarkMembersAsStatic",
Justification = "This non-static member is needed for data binding purposes.")]
public MainPageViewModel MainPage
{
get
{
return ServiceLocator.Current.GetInstance<MainPageViewModel>();
}
}
static ViewModelLocator()
{
// DEBUG LINE: var test = Views.ViewLocator.MainPageKey;
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
if (ViewModelBase.IsInDesignModeStatic)
{
SimpleIoc.Default.Register<IDataService, Design.DesignDataService>();
}
else
{
SimpleIoc.Default.Register<IDataService, DataService>();
}
SimpleIoc.Default.Register<MainPageViewModel>();
}
}
I have another class, a ViewLocator, for navigation purposes which looks like this:
public class ViewLocator
{
public static readonly string MainPageKey = typeof(MainPage).Name;
public static readonly string WorkPageKey = typeof(WorkPage).Name;
static ViewLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
var navigationService = new NavigationService();
navigationService.Configure(MainPageKey, typeof(MainPage));
navigationService.Configure(WorkPageKey, typeof(WorkPage));
SimpleIoc.Default.Register<INavigationService>(() => navigationService);
SimpleIoc.Default.Register<IDialogService, DialogService>();
}
}
Before, both classes were combined in ViewModelLocator, however i figured that the ViewModelLocator as part of the "ViewModels-Side-of-things" should be unaware of the views and it's types, which is why I refactored that code into two classes.
My MainPageView then has a button, which triggers a navigation command in the MainPageView.cs
public class MainPageViewModel : ViewModelBase
{
private INavigationService _navigationService;
public RelayCommand CreateNewImageCommand { get; private set; }
public MainPageViewModel(INavigationService navigationService)
{
_navigationService = navigationService;
CreateNewImageCommand = new RelayCommand(CreateNewImage, () => true);
}
public void CreateNewImage()
{
_navigationService.NavigateTo(Views.ViewLocator.WorkPageKey);
}
}
For completeness, here is my App.xaml
<Application
...>
<Application.Resources>
<v:ViewLocator x:Key="ViewLocator" />
<vm:ViewModelLocator x:Key="ViewModelLocator" />
</Application.Resources>
Now what happens is this: if I don't have the DEBUG LINE in ViewModelLocator, at the point at which MainPage requests its ViewModel from the ViewModelLocator, the constructor of ViewLocator has not been called yet and return ServiceLocator.Current.GetInstance<MainPageViewModel>();
throws an exception. If I include the DEBUG LINE, this forces the ViewLocator Constructor to be run first, and everything works fine.
How can I achieve this behaviour without that odd debug line?