简体   繁体   中英

IDataService is already registered in MVVM Light Project

I'm trying to adjust my WP8 project from self made MVVM implementation to MVVM Light. I've successfully worked through this example and it worked perfectly. I've then started to repeat the same steps for my own project.

The application compiles without errors, but when I open my MainPage.xaml in Expression Blend, I will get this error:

Class project.Services.IDataService is already registered. App.xaml, Line 6, Column 5

If I look it up, it's the line where the ViewModelLocator is registered:

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

My 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>();
        }

As you can see from my code comment, I've already tried the fix supposed here , but I'm still getting this error in Blend. There is no other place left where I could register the IDataService, so what could be the problem? Other questions here on SO are especially for desktop applications and does also only contain some kind of the above fix where there's first a check before the ViewModelLocator is registered.

Any ideas? :)

Update 1: I've managed to display my design time in Visual Studio. I was still manually referencing the DataContext in my Code Behind File. However, I still need to solve the problem that I cannot display the design time data in Blend. Judging from Visual Studios behavior it should work though?!

I had the same issue, and this seems to be a Visual Studio issue in combination with XAML-Designer, Static Factories/Locators and Design-Time creation of objects. However: The solutions were the following:

  1. Register without a factory (not recommended)

    SimpleIoc.Default.Register<INavigationService>();

  2. Or if you want to use a factory, unregister before registering the factory

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

  3. Prevent the ViewModelLocator from being created more than once by the designer/Blend by making the constructor static

    static ViewModelLocator() { ... }

The error is cumbersome but could happen in this scenario: You create objects during design-time (the ViewModelLocator within App.xaml probably) and whenever you change something in your Code, the Compiler is triggered and the ViewModelLocator gets re-created without ever unregistering the services. Therefore it will complain that in the factory has already been registered. In theory, when registering classes without factories multiple times, there should be an error as-well.

Old question, but still relevant, and I don't think the cause has been explained yet, nor a direct answer to it.

When in design time, it seems that Visual Studio likes to instantiate resources multiple times.
This causes a view model locator, which is presumably defined in your App.xaml, or some other resource, to be constructed multiple times, in the same static application instance.

The SimpleIoc.Default exist as a single instance across these 2 view model locator instances, causing any new registrations to be duplicate registrations.

It might seem to work at first after restarting Visual Studio, reloading your project, or killing XDesProc.exe (host process for the XAML designer in Visual Studio), but if you close a window designer, and open it again, you'll get the design time error, because it's trying to re-create the resources linked to that window.

I've tried several solutions, like making a static boolean in the view model locator, that I'd set to true on the first call, and if it's true before that, return, and don't register anything.

But unfortunately, this doesn't seem to help, as the boolean got re-instantiated along with the view model locator.
One could try to put it in a separate class that isn't being re-constructed every time a view is opened, but this seemed slightly silly.

Finally, I decided to use the .Reset() method on SimpleIoc in order to remove all previously registered services, instances and factories.

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

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

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

This seems to solve the issue, and should have no effect in runtime, as the view model locator will only get instantiated once.

After reading the comments from the ViewModelLocator.cs again and again, I've seen that the DataContext for my MainPage.xaml was not set correctly:

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

instead of

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

The Error in Blend stopped and I can see now in Blend and in VS the same design time data. But how did I oversee this error? Well, here's the explanation:

I've oriented myself on this tutorial , which was quite helpful. But my experience was, that it must be for some kind of older version of MVVM Light and something changed in the version I'm using now. Jesse used the Binding without the Path. However, this is working in his example. But here in my special case I needed to supply the Path so that the Locator could identify the correct property for my MainViewModel (which is here Main).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM