【问题标题】:ViewModels in ViewModelLocator MVVM LightViewModelLocator MVVM Light 中的 ViewModel
【发布时间】:2013-01-02 22:34:16
【问题描述】:

将我所有的 ViewModel 存储在 SimpleIoc 中是否正确?例如,我有三个页面 MainPage、Photos、Directories(因此三个 ViewModels -> MainVM、PhotosVM、DirectoriesVM)。我应该将每个页面中的 DataContext 设置为 ViewModelLocator 中的 View Model Property 还是将 ViewModels 嵌套为 MainVM 中的属性并将每个页面 DataContext 绑定到 Main.PhotosVMProperty、Main.DirectoriesVMProperty 等等?谁能解释一下 IoC 的想法和目的?

【问题讨论】:

  • 希望对您有所帮助:stackoverflow.com/questions/13795596/…
  • 您能提供一些与您的第二种方法相关的代码吗?您如何在 MainViewModel 中定义 PhotosVMProperty...您的问题很有趣...

标签: xaml mvvm-light


【解决方案1】:

首先,让我们看看 ViewModelLocator 的作用以及我们使用它的原因:

ViewModelLocator 在我们的 App.xaml 页面上被声明为一个对象,并且是一个应用程序单例。我们将拥有一个,并且只有其中一个可供应用程序运行时使用。

ViewModelLocator 是 MVVM Light 中所有 ViewModel 的来源。对于每个 ViewModel,我们将在 ViewModelLocator 上拥有一个属性,该属性允许我们获取 View 的 ViewModel。此代码如下所示:

public class ViewModelLocator
{
    public MainPageViewModel MainPage
    {
        get { return new MainPageViewModel(); }
    }
}

这是我的 App.xaml 的一部分:

<Application.Resources>
    <vm:ViewModelLocator
        x:Key="ViewModelLocator" />
</Application.Resources>

这是来自 View.xaml 的一部分

DataContext="{Binding MainPage, Source={StaticResource ViewModelLocator}}"

到目前为止一切顺利。要回答您的第一个问题,您是否必须在 MVVM Light 中使用 Ioc?不。没有必要,因为您的视图模型将提供给由 ViewModelLocator 完全构建和实例化的视图。

现在,进入第二个问题:IoC 的目的是什么?

IoC 旨在让您执行以下操作:

使用 Mvvm Light,您可以像这样执行上述操作:

public class ViewModelLocator
{
    public ViewModelLocator()
    {
        ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);

        if (ViewModelBase.IsInDesignModeStatic)
        {
            SimpleIoc.Default.Register<IDataService, Design.DesignDataService>();
        }
        else
        {
            SimpleIoc.Default.Register<IDataService, DataService>();         
        }

        SimpleIoc.Default.Register<MainViewModel>();
    }

    public MainViewModel Main
    {
        get { return SimpleIoc.Default.GetInstance<MainViewModel>(); }
    }
}

public class MainViewModel
{
    public ObservableCollection<Foo> Foos { get; set; }

    public MainViewModel(IDataService dataService)
    {
        _dataService=dataService;
        Foos=_dataService.GetFoos();
    }
}

当我调用时解析 MainViewModel 时

SimpleIoc.Default.GetInstance<MainViewModel>()

内部发生的是 SimpleIoc 检查 MainViewModel 是否有任何依赖项(其构造函数中的参数)。然后,它会尝试通过查看已注册的接口来解析这些参数。它以递归方式执行此操作,因此如果 DataService 具有依赖关系,它也会在实例化时被实例化并传递给 DataService 构造函数。

我为什么要做所有这些工作?

  1. 让您的课程易于单元测试
  2. 使您的代码界面驱动。这意味着您引用的是接口而不是具体的类
  3. 使您的代码松散耦合。这意味着某人可以更改接口的实现,而使用该接口的类不需要重新编码。
  4. 以自动方式解决您的类依赖关系。
  5. 在 MVVM Light 中,您会看到它可以判断何时在设计模式下运行 (ViewModelBase.IsInDesignModeStatic),这意味着您可以创建设计时服务来提供您的视图模型数据,以便您在 Visual Studio 中的视图包含实际数据。

【讨论】:

  • 对主题的出色分解和响应。谢谢。
  • 完美,节省了我很多时间。
  • ...如果您想知道您的输入是否会影响多年,是的。这正是那种帮助我理解正在发生的事情的分解和演练。谢谢!
  • @Faster Solutions ,它是否可混合?意味着在视图模型中没有参数少的构造函数,混合将无法获取数据绑定的视图模型对吗?
【解决方案2】:

MVVM Light 有很多不错的功能,但在我看来,Service Locator 创建了视图对视图模型的不必要依赖。理想情况下,我希望在库 A 中拥有 ViewModelLocator,在库 B 中拥有视图模型,在库 C 中拥有视图。然后我可以根据未来项目的需要混合和匹配这些。但是,在 MVVM Light 的设计中,据我所知,视图(库 C)将始终依赖于 ViewModelLocator(这没关系),但是因为 ViewModelLocator(库 A)将始终依赖于视图模型(库 B),那么视图将始终依赖于视图模型(这是不行的,因为视图现在必须包含它曾经在所有产品中使用过的所有视图模型库)。

我相信 Prism 以某种方式使用字符串键来解决这个问题。我错过了什么吗?

哎呀!我想我只是回答了我自己的问题。解决方案是使库 A(ServiceLocator)特定于特定的解决方案(产品)。然后它只包含对该解决方案的视图模型的引用。然后视图依赖于这个 ServiceLocator,而后者又依赖于该产品的所有视图模型。最终结果是视图仅取决于将用于该产品的视图模型。事实上,我们为每个解决方案复制 ServiceLocator 是没有问题的,因为这个模块只包含特定于解决方案的代码。 ServiceLocator 的组件(例如 SimpleIoc 类)当然对所有解决方案都是通用的,但这些组件已被分解为我们在 ServiceLocator 中调用的可重用类。

总而言之,我要解决的问题是假设一个解决方案有 6 个视图模型,其中四个密切相关,其中两个密切相关。因此,我们创建了两个程序集,每个程序集都包含密切相关的视图模型。假设我们设计了一个使用一组视图模型的产品,并且该解决方案设计为运行 Windows 8。现在视图都不同了,我们只想重用一组(组合)视图模型。因此,我们只需创建一个新的 ServiceLocator 程序集,它指向该视图模型程序集以及我们需要的任何其他程序集。我们新的 Windows 8 视图现在依赖于这个新的 ServiceLocator 程序集,并且仅依赖于我们的新产品(解决方案)中使用的视图模型。

【讨论】:

    猜你喜欢
    • 2016-06-21
    • 2014-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-08
    相关资源
    最近更新 更多