我正在开发一个使用ViewModelLocator的C#/ WPF / MVVM / UWP应用程序,如下所示:
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>();
}
}
我有另一个类,一个ViewLocator,用于导航目的,如下所示:
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>();
}
}
之前,两个类都在ViewModelLocator中合并,但是我认为ViewModelLocator是&#34; ViewModels-Side-of-things&#34;应该不知道视图和它的类型,这就是我将该代码重构为两个类的原因。
我的MainPageView然后有一个按钮,它在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);
}
}
为了完整性,这是我的App.xaml
<Application
...>
<Application.Resources>
<v:ViewLocator x:Key="ViewLocator" />
<vm:ViewModelLocator x:Key="ViewModelLocator" />
</Application.Resources>
现在发生的事情是:如果我在ViewModelLocator中没有DEBUG LINE,那么在MainPage从ViewModelLocator请求其ViewModel的时候,ViewLocator的构造函数尚未被调用{{1}抛出一个异常。如果我包含DEBUG LINE,这会强制首先运行ViewLocator构造函数,一切正常。
如果没有那个奇怪的调试行,我怎么能实现这种行为?
答案 0 :(得分:0)
您遇到了大多数开发人员不使用静态类和服务定位器的原因。
正如您的评论中所建议的那样尝试使用依赖注入。这允许反转对管理此布线的组件的控制。
将MEF或Unity视为一个使用而不是滚动自己的IoC的框架。两者都有优点和缺点,但两者都有效。它们还允许更容易和更清洁的测试。
答案 1 :(得分:0)
尽管有所有的评论和其他答案,我认为我毕竟是在赛道上。为了解决或者更好地绕过这个问题,我在应用程序的启动中创建了SimpleIoC容器的附加引导,并从ViewLocator
的构造函数中移动代码。
我还删除了ServiceLocator调用,这有点多余,现在直接依赖SimpleIoC.Default
。
导航器仍由SimpleIoC
容器注入ViewModel。但是,ViewModelLocator必须与XAML代码结合使用。
我建议将这个答案作为其他正在努力解决这个问题的人的起点。
https://stackoverflow.com/a/25524753/2175012
毕竟,我认为ServiceLocators没有反模式,但必须小心使用。