【问题标题】:MVVM Light - PCL+WPF - Getting exception of type Microsoft.Practices.ServiceLocation.ActivationExceptionMVVM Light - PCL+WPF - 获取 Microsoft.Practices.ServiceLocation.ActivationException 类型的异常
【发布时间】:2016-02-15 21:33:52
【问题描述】:

背景

嗨,所有 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 未被用户代码处理

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

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

你们有什么可以告诉我的,也许博客作者跳过了我需要做的事情吗?也许如果向这块“巨石”扔足够多的石头,它就会裂开……

澄清

我的 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(DeviceLocatorService,位于 WPF 项目中)

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&lt;IMainViewModel&gt;(); 行出现错误(仅在调试时)。

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>

【问题讨论】:

  • 适用于 Windows 的 WPF?我不太明白你的目标是什么平台。
  • 它是跨平台的。我正在开发的两个平台是适用于 Windows 的 WPF 和适用于 Android 的 Android 哈哈。您在 PCL 中有“通用”代码,可以在两个平台之间共享,同时在他们自己的项目中拥有特定于平台的代码。
  • @Steven_BDawg 你能展示你的 DeviceLocatorService 吗?因为我认为 IStorageService 没有在 IoC 容器中注册。
  • @Valentin 已添加!同样,这是我通过博客 1、博客 2、博客 3 遵循的指南。
  • @Steven_BDawg 能否请您在 DeviceLocatorService ctor 中放置一个断点,在 LocatorService ctor 中放置另一个断点?我认为它在 DeviceLocatorService 的 ctor 之前调用了 LocatorService 的 ctor。在我的机器代码上工作正常。

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


【解决方案1】:

我的问题的解决方案比人们想象的要简单。 WPF 应用程序使用MVVM 工具包/框架没有问题,但它们似乎在共享方面存在问题。由于WPF 并非旨在成为一种跨平台友好的语言,因此编写此类内容的“正确”方法将不适合它。

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

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

【讨论】:

    【解决方案2】:

    我认为,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>
    

    【讨论】:

    • 您现在看到我已经添加了它,DeviceLocatorServiceApp.xaml 中。
    • @Steven_BDawg 你能尝试在 App.xaml 中使用一个命名空间吗?
    • 我正在使用一个命名空间。
    • @Steven_BDawg 您正在使用 2 xmlns:services="clr-namespace:StackOverF.Services;assembly=StackOverF.PCL" xmlns:deviceServices="clr-namespace:StackOverF.Services"
    • @Steven_BDawg 是否调用DeviceLocatorService 构造函数?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-19
    • 2014-12-21
    相关资源
    最近更新 更多