MVVM Light - PCL + WPF - 获取Microsoft.Practices.ServiceLocation.ActivationException

时间:2016-02-15 21:33:53

标签: wpf mvvm-light portable-class-library

背景

大家都是SO观众。我通常是Android开发人员,但现在我正在开发针对WPF和Android的跨平台应用程序。话虽如此,几乎没有关于如何直接做我想要的信息。因此,我最终找到了一个由3部分组成的博客系列,深入探讨了如何开发基于Windows的跨平台MVVM项目。只要我将PCL设置为与Xamarin.Android兼容,任何不会抛出错误的代码应该在我进入Android方面时起作用。以下是博文的链接:Blog 1Blog 2Blog 3。我再次使用Android,因此我不熟悉为WPF应用程序编写代码。

问题

所以我今天的问题只涉及PCL-WPF方面,这与上面链接的博客文章有关。我尽可能地遵循帖子中的每一步。该博客使用WinRT和WinPhone作为两个目标平台,所以我不得不尝试自己搞清楚,以便在WPF上运行。我必须做的两件事是使用IsolatedStorage并基本上使用WinPhone App.Xaml来构建WPF。

我已经完成了博客一直到最后并构建成功。我甚至可以在第三篇博文的末尾看到我的示例调试行。但是,当我去运行它时,我得到以下内容:

  

ActivationException未被用户代码

处理      

GalaSoft.MvvmLight.Extras.dll中出现“Microsoft.Practices.ServiceLocation.ActivationException”类型的异常,但未在用户代码中处理

     

$ exception {Microsoft.Practices.ServiceLocation.ActivationException:在缓存中找不到类型:StackOverF.Services.IStorageService。      atC:\ MvvmLight \ Source \ GalaSoft.MvvmLight \ GalaSoft.MvvmLight.Extras(PCL)\ Ioc \ SimpleIoc.cs:line 537中的GalaSoft.MvvmLight.Ioc.SimpleIoc.DoGetService(类型serviceType,String key,Boolean cache)      atC:\ MvvmLight \ Source \ GalaSoft.MvvmLight \ GalaSoft.MvvmLight.Extras(PCL)\ Ioc \ SimpleIoc.cs:line 789中的GalaSoft.MvvmLight.Ioc.SimpleIoc.GetService(类型serviceType)      at c:\ MvvmLight \ Source \ GalaSoft.MvvmLight \ GalaSoft.MvvmLight.Extras(PCL)\ Ioc \ SimpleIoc.cs:line 729中的GalaSoft.MvvmLight.Ioc.SimpleIoc.MakeInstanceTClass} System.Exception {Microsoft.Practices.ServiceLocation。 ActivationException}

你们有什么东西可以告诉我,博客作者可能会跳过我需要做的事吗?也许如果在这块“巨石”上扔出足够的岩石,它就会开裂......

澄清

我的Visual Studio解决方案目前基本上只有两个项目。一个是可移植类库。另一个是WPF应用程序。在不久的将来,一旦我开始在WPF方面工作,我将使用Xamarin中的PCL来重用Android项目中的代码。但是,Android方面是我问题的一部分。我只处理WPF项目时遇到了上述问题。

代码(最后编辑2016年2月18日)

IMainViewModel.cs

using GalaSoft.MvvmLight.Command;
using StackOverF.Models;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace StackOverF.ViewModels {
    public interface IMainViewModel {
        ObservableCollection<Workload> Workload { get; }

        RelayCommand RefreshCommand { get; }
        RelayCommand AddCommand { get; }
    }
}

MainViewModel.cs

using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using StackOverF.Models;
using StackOverF.Services;
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


namespace StackOverF.ViewModels {
    public class MainViewModel : ViewModelBase,IMainViewModel {

        private IDataService dataService;

        public MainViewModel(IDataService dataService) {
            this.dataService = dataService;

            RefreshAsync();
        }

        private ObservableCollection<Workload> workload = new ObservableCollection<Workload>();
        public ObservableCollection<Workload> Workload {
            get {
                return workload;
            }
        }

        #region Commands

        #region Refresh
        private RelayCommand refreshCommand;
        public RelayCommand RefreshCommand {
            get {
                return refreshCommand ?? (refreshCommand = new RelayCommand(async () => { await RefreshAsync();}));
            }
        }

        private async Task RefreshAsync() {
            workload.Clear();
            foreach (Workload listing in await dataService.GetWorkloadAsync()) {
                workload.Add(listing);
            }
        }
        #endregion

        #region Add
        private RelayCommand addCommand;
        public RelayCommand AddCommand {
            get {
                return addCommand ?? 
                    (addCommand = new RelayCommand(async () => { 
                        Workload listing = new Workload() { Id = 3, Serial = "relay12" };
                        await dataService.AddWorkloadAsync(listing);
                        workload.Add(listing);
                    }));
            }
        }
        #endregion

        #endregion
    }
}

LocatorService.cs(位于WPF项目中的DeviceLocatorService)

using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Ioc;
using Microsoft.Practices.ServiceLocation;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace StackOverF.Services {
    public class DeviceLocatorService {
        static DeviceLocatorService() {
            ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);

            if (ViewModelBase.IsInDesignModeStatic) {
            }
            else {
            }

            if (!SimpleIoc.Default.IsRegistered<IStorageService>()) 
                SimpleIoc.Default.Register<IStorageService, StorageService>();
        }

        public static void Cleanup() {
        }
    }
}

LocatorService.cs(LocatorService,位于PCL项目中)

using Microsoft.Practices.ServiceLocation;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Ioc;
using StackOverF.ViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace StackOverF.Services {
    public class LocatorService {
        static LocatorService() {
            ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);


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

            // View Models
            SimpleIoc.Default.Register<IMainViewModel, MainViewModel>();
        }

        public IMainViewModel MainViewModel {
            get {
                return ServiceLocator.Current.GetInstance<IMainViewModel>();
            }
        }

        public static void Cleanup() {
        }
    }
}

return ServiceLocator.Current.GetInstance<IMainViewModel>();行发生错误(仅限调试)。

的App.xaml

<Application x:Class="StackOverF.App"
             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:d="http://schemas.microsoft.com/expression/blend/2008"
             mc:Ignorable="d"   
             xmlns:services="clr-namespace:StackOverF.Services;assembly=StackOverF.PCL"
             xmlns:deviceServices="clr-namespace:StackOverF.Services"
             StartupUri="Views/MainWindow.xaml">
    <Application.Resources>
        <ResourceDictionary>
            <deviceServices:DeviceLocatorService x:Key="Locator.WPF" d:IsDataSource="True" />
            <services:LocatorService x:Key="Locator" d:IsDataSource="True" />
        </ResourceDictionary>
    </Application.Resources>
</Application>

2 个答案:

答案 0 :(得分:1)

我的问题的解决方案比人们预期的更简单。 WPF应用程序使用MVVM工具包/框架没有问题,但它们似乎确实存在共享问题。由于WPF并非旨在成为一种跨平台友好的语言,因此&#34;正确&#34;对这样的事情进行编程的方法不会起作用。

问题在于尝试在LocatorService中包含App.xaml个类,并期望WPF同时运行WinRTWinPhone这两个类。如果需要数据,WPF似乎只引用一个类。就像在博客的示例中一样,我在Main.xaml类中绑定了LocatorService类。由于WPF应用程序只运行该类的代码,因此它会抛出错误。

解决方案是将LocatorService文件合并到WPF项目端的一个文件中。为什么在WPF方面问你? Portable Class Library应该只包含通用代码,可共享的跨平台。

答案 1 :(得分:0)

我认为,IoC容器正在尝试解析MainWindow并使容器解析IDataService。但是IDataService具有依赖IStorageService,它没有在IoC容器中注册。

在我看来,IStorageService未注册,因为永远不会调用DeviceLocatorService构造函数。

我认为您遇到app.xaml

的问题
<Application
    x:Class="SampleApp.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:ignore="http://www.ignore.com"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"    
    mc:Ignorable="d ignore"    
    xmlns:services="using:SampleApp.Services"   
    xmlns:local="using:SampleApp">

    <Application.Resources>
        <ResourceDictionary>

            <services:LocatorService x:Key="Locator" d:IsDataSource="True" />
            <services:DeviceLocatorService x:Key="Locator.W8" d:IsDataSource="True" />
        </ResourceDictionary>
    </Application.Resources>
</Application>