确保在另一个之前创建一个静态类

时间:2016-05-12 16:12:44

标签: c# wpf mvvm static-classes

我正在开发一个使用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构造函数,一切正常。

如果没有那个奇怪的调试行,我怎么能实现这种行为?

2 个答案:

答案 0 :(得分:0)

您遇到了大多数开发人员不使用静态类和服务定位器的原因。

正如您的评论中所建议的那样尝试使用依赖注入。这允许反转对管理此布线的组件的控制。

将MEF或Unity视为一个使用而不是滚动自己的IoC的框架。两者都有优点和缺点,但两者都有效。它们还允许更容易和更清洁的测试。

MEF

Unity

答案 1 :(得分:0)

尽管有所有的评论和其他答案,我认为我毕竟是在赛道上。为了解决或者更好地绕过这个问题,我在应用程序的启动中创建了SimpleIoC容器的附加引导,并从ViewLocator的构造函数中移动代码。

我还删除了ServiceLocator调用,这有点多余,现在直接依赖SimpleIoC.Default

导航器仍由SimpleIoC容器注入ViewModel。但是,ViewModelLocator必须与XAML代码结合使用。

我建议将这个答案作为其他正在努力解决这个问题的人的起点。

https://stackoverflow.com/a/25524753/2175012

毕竟,我认为ServiceLocators没有反模式,但必须小心使用。