4

我正在尝试将我的 WP8 项目从自制的 MVVM 实现调整为 MVVM Light。我已经成功地完成了这个例子,并且效果很好。然后我开始为我自己的项目重复相同的步骤。

应用程序编译时没有错误,但是当我在 Expression Blend 中打开 MainPage.xaml 时,我会收到以下错误:

类 project.Services.IDataService 已注册。App.xaml,第 6 行,第 5 列

如果我查找它,它是 ViewModelLocator 注册的行:

<Application.Resources>
<vm:ViewModelLocator x:Key="Locator" d:IsDataSource="True" />
</Application.Resources>

我的 ViewModelLocator.cs:

        /// <summary>
        /// Initializes a new instance of the ViewModelLocator class.
        /// </summary>
        public ViewModelLocator()
        {
            ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);

            if (ViewModelBase.IsInDesignModeStatic)
            {
                // Create design time view services and models
                // see: http://developingux.com/2012/06/10/how-to-fix-error-design-time-data-in-blend-with-mvvm-light/
                if (!SimpleIoc.Default.IsRegistered<IDataService>())
                {
                    SimpleIoc.Default.Register<IDataService, DesignDataService>();
                }
            }
            else
            {
                // Create run time view services and models
                if (!SimpleIoc.Default.IsRegistered<IDataService>())
                {
                    SimpleIoc.Default.Register<IDataService, DataService>();
                }
            }

            // only one ViewModel for the MainPage
            SimpleIoc.Default.Register<MainViewModel>();
        }

正如您从我的代码注释中看到的那样,我已经尝试过这里假设的修复,但我仍然在 Blend 中遇到此错误。没有其他地方可以注册 IDataService,那么可能是什么问题?SO 上的其他问题特别针对桌面应用程序,并且也仅包含上述某种修复,其中在注册 ViewModelLocator 之前首先进行检查。

有任何想法吗?:)

更新 1: 我已经设法在 Visual Studio 中显示我的设计时间。我仍然在我的代码隐藏文件中手动引用 DataContext。但是,我仍然需要解决无法在 Blend 中显示设计时数据的问题。从 Visual Studios 的行为来看,它应该可以工作吗?!

4

3 回答 3

5

老问题,但仍然相关,我认为原因尚未得到解释,也没有直接答案。

在设计时,Visual Studio 似乎喜欢多次实例化资源。
这会导致在同一个静态应用程序实例中多次构造视图模型定位器,该定位器可能在您的 App.xaml 或其他资源中定义。

在这SimpleIoc.Default2 个视图模型定位器实例中作为单个实例存在,导致任何新注册都是重复注册。

在重新启动 Visual Studio、重新加载项目或杀死(Visual Studio 中 XAML 设计器的宿主进程)之后,它可能一开始似乎可以工作XDesProc.exe,但如果你关闭一个窗口设计器,然后再次打开它,你将获得设计时间错误,因为它试图重新创建链接到该窗口的资源。

我尝试了几种解决方案,比如在视图模型定位器中创建一个静态布尔值,我在第一次调用时将其设置为 true,如果在此之前为 true,则返回,并且不注册任何内容。

但不幸的是,这似乎没有帮助,因为布尔值与视图模型定位器一起被重新实例化。
可以尝试将它放在一个单独的类中,每次打开视图时都不会重新构建它,但这似乎有点愚蠢。

最后,我决定使用.Reset()on 方法SimpleIoc来移除所有之前注册的服务、实例和工厂。

public ViewModelLocator()
{
    SimpleIoc.Default.Reset();

    ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);

    SimpleIoc.Default.Register<IExampleService, ExampleServiceImplementation>();
    // Register the rest of your services
}

这似乎解决了这个问题,并且在运行时应该没有影响,因为视图模型定位器只会被实例化一次。

于 2017-03-31T21:45:17.103 回答
4

我遇到了同样的问题,这似乎是与 XAML 设计器、静态工厂/定位器和对象的设计时创建相结合的 Visual Studio 问题。但是:解决方案如下:

  1. 无工厂注册(不推荐)

    SimpleIoc.Default.Register<INavigationService>();

  2. 或者如果您想使用工厂,请在注册工厂之前取消注册

    SimpleIoc.Default.Unregister<INavigationService>(); SimpleIoc.Default.Register<INavigationService>(() => new NavigationService());

  3. 通过将构造函数设为静态,防止设计器/Blend 多次创建 ViewModelLocator

    static ViewModelLocator() { ... }

该错误很麻烦,但可能在这种情况下发生:您在设计时(ViewModelLocator可能在 App.xaml 中)创建对象,并且每当您更改代码中的某些内容时,都会触发编译器并重新创建 ViewModelLocator,而无需取消注册服务。因此它会抱怨在工厂已经注册。理论上,当多次注册没有工厂的类时,也应该有错误。

于 2015-03-07T14:14:06.273 回答
-2

在一次又一次地阅读 ViewModelLocator.cs 的评论后,我发现我的 MainPage.xaml 的 DataContext 设置不正确:

DataContext="{Binding Source={StaticResource Locator}, Path=Main}"

代替

DataContext="{Binding Main, Source={StaticResource Locator}}"

Blend 中的错误停止了,我现在可以在 Blend 和 VS 中看到相同的设计时数据。但是我是如何监督这个错误的呢?好吧,这是解释:

我已经将自己定位于本教程,这非常有帮助。但我的经验是,它必须适用于某种旧版本的 MVVM Light,并且我现在使用的版本发生了一些变化。Jesse 使用了没有路径的绑定。但是,这在他的示例中有效。但是在我的特殊情况下,我需要提供路径,以便定位器可以识别我的 MainViewModel 的正确属性(这里是 Main)。

于 2013-01-04T08:47:35.827 回答