【问题标题】:MVVM Light ViewModelLocatorMVVM Light ViewModelLocator
【发布时间】:2014-08-29 17:58:29
【问题描述】:

我在我的应用程序中使用 MVVM Light,解决方案中有多个程序集。 如何在不定义 App.xaml 资源的情况下在每个程序集中拥有一个 ViewModelLocator?

通常 ViewModelLocator 是这样定义的:

<Application.Resources>
  <ResourceDictionary>
   <ResourceDictionary.MergedDictionaries>
     <ResourceDictionary Source="/Sol1;component/GlobalResources.xaml" />
   </ResourceDictionary.MergedDictionaries>
   <viewModels:ViewModelLocator xmlns:main="clr-namespace:MainModule.ViewModel;assembly=MainModule" x:Key="Locator" d:IsDataSource="True"/> 
</ResourceDictionary>

我在我的解决方案中的类库中创建了一个 Resources.xaml,如下所示:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                xmlns:ModuleX="clr-namespace:ModuleX">
<ResourceDictionary.MergedDictionaries>
    <ResourceDictionary Source="/Common;component/CommonResources.xaml" />
</ResourceDictionary.MergedDictionaries>
<ModuleX:ViewMoldelLocator x:Key="ModuleXLocator" />
</ResourceDictionary>

但是,找不到 ModuleXLocator:

<phone:PhoneApplicationPage
       ...
       DataContext="{Binding Main, Source={StaticResource ModuleXLocator}}">

【问题讨论】:

    标签: xaml windows-phone-8 mvvm mvvm-light


    【解决方案1】:

    如果我回答您的问题,我不是 100%,但我会回答我遇到的类似问题及其解决方案。希望它是您正在寻找的东西。

    问题:

    您已经设计了一个很棒的小型 MVVMLight 应用程序 (LittleApp),现在您想将它用作另一个项目 (BigApp) 中的 UserControl/Page/Window。问题是 LittleApp 在其对应的 App.xaml 中定义了它的 ViewModelLocator,而 BigApp 不使用它。结果是 LittleApp 在“BigApp's App.xaml”中查找其 ViewModelLocator 并失败。

    您还想让 LittleApp 作为一个独立的项目工作,因此不想弄乱它的设计。

    给出可能的例外情况:

    XMLParseException:在 LittleApp 的根节点中定义的 ViewModelLocator 找不到(因为它定义在一个未使用的 App.xaml 中)

    WPFError 40:您已使用 MVVMLight 工具创建了这两个应用程序,因此这两个应用程序都有一个 App.xaml,其中一个名为“Locator”的 ViewModelLocator 指向一个名为“Main”的 ViewModel。 LittleApp 将能够解决这个问题,但它会指向错误的 MainViewModel,从而产生属性冲突。

    解决方案:

    您需要在 LittleApp 的 MainView 的根节点中将 LittleApp 的 ViewModelLocator 定义为资源。因此,如果您的 MainView 是一个名为 LittleApp/View/MainView.xaml 的 UserControl,它将看起来像这样。

    <UserControl x:Class="LittleApp.View.MainView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:vm="clr-namespace:LittleApp.ViewModel"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    
        <UserControl.Resources>
            <ResourceDictionary>
                <ResourceDictionary.MergedDictionaries>
                    <ResourceDictionary Source="../Skins/MainSkin.xaml" />
                </ResourceDictionary.MergedDictionaries>
                <vm:ViewModelLocator x:Key="Locator"/>
            </ResourceDictionary>
        </UserControl.Resources>
    
        <UserControl.DataContext>
            <Binding Source="{StaticResource Locator}"/>
        </UserControl.DataContext>
    
        <Grid>
           .
           .  Your Control Design
           .
           .
           .
        </Grid>
    </UserControl>
    

    现在 BigApp 只需要引用 LittleApps 程序集并将其作为命名空间添加到要添加到的控件的根节点中。像这样。

    <Page x:Class="BigApp.View.Page1"
          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
          xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"      
          xmlns:LittleView="clr-namespace:LittleApp.View;assembly=LittleApp"
          xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
          mc:Ignorable="d" 
          d:DesignHeight="300" d:DesignWidth="300">
    
        <Grid>
            <LittleView:MainView/>
        </Grid>
    </Page>
    

    【讨论】:

    • 感谢您的回答!你肯定带我走对了路。实际上,我在 LittleAppResources.xaml 中添加了 ,然后在每个视图中,我通过 ResourceDictionary 添加了对该 xaml 的引用,就像您在 UserControl 中所做的那样。 :)
    • 这个答案直接解决了我的一个问题,谢谢!但问题是:这会导致 LittleApp 的 VML 覆盖 BigApp 的吗?如何在 VML 之间共享数据? (例如,我不希望每个 LittleApp 窗口都必须重新加载父级已从磁盘加载的数据,但我不希望多个 LittleApp 共享状态。
    • @metao 你不应该在 VMLocator 之间共享信息。每个项目都应该有一个 VML,它将视图链接到它们各自的视图模型。如果它们具有父子关系,则父视图模型应创建并包含每个子视图模型,您可以直接在它们之间传递信息或使用信使服务。然后在 xaml 中,BigApp 的数据上下文将是 (Locator.)Main(在 app.xaml 中设置),您可以在代码或 BigApp 的 xaml 中将 LittleApps 数据上下文设置为与 (Locator.)Main.LittleAppViewModel 的绑定。跨度>
    • @metao LittleApp 的所有元素都将继承这个新的数据上下文,并通过在自己的项目中定义的绑定正确地填充视图。值得注意的是,如果您使用 mvvmLight,您可以使用 SimpleIoC 在 BigApps VML 中注册 LittleApp 的 MainViewModel - 例如 SimpleIoc.Default.Register();。然后您可以在 BigApp 的 MainViewModel 中调用现有/新实例(例如在构造函数中)LittleAppViewModel = ServiceLocator.Current.GetInstance()。这就是您随后绑定为数据上下文的内容。
    • @Josh C 在我寻求改进 MVVM 实施的过程中,您的回答非常有帮助。但是,我无法从 XAML 中获取 ViewModelLocator 的概念。当我使用您的方法时,数据绑定失败,因为它在“定位器”对象而不是 ViewModel 上查找属性。但是,如果我使用 SimpleIoc ServiceLocator 在代码隐藏中分配 DataContext,一切正常。你对我如何让它从 XAML 工作有什么建议吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-03
    • 2016-06-21
    • 1970-01-01
    • 2016-12-26
    • 1970-01-01
    • 2015-08-02
    相关资源
    最近更新 更多