Background
Hi all SO viewers. I am normally an Android developer, but now I'm developing a cross platform application targeting WPF and Android. That being said, there's practically no info on how to directly do what I want. So, I ended up finding a 3-part blog series that goes in depth on how to develop a Windows-based cross platform MVVM project. As long as I set the PCL to be compatible with Xamarin.Android, any code that doesn't throw an error SHOULD work once I get to the Android side of things. Here are the links to the blog posts: Blog 1, Blog 2, Blog 3. Again, I do Android, so I am new to doing coding for a WPF Application.
Issue
So my issue today is only dealing with the PCL-WPF side which relates to the above-linked blog post. I followed every single step laid out in the posts as best as I could. The blog uses WinRT and WinPhone as the two target platforms, so I HAD to try figuring out things on my own to make things work on the WPF. Two of the things I had to do was use IsolatedStorage
and basically use the WinPhone App.Xaml
to make the WPF side build.
I have finished the blog all the way to the end and build succeeds. I even can see my example Debug lines like it talks about at the end of the third blog post. However, when I go to run it, I get the following:
ActivationException was unhandled by user code
An exception of type 'Microsoft.Practices.ServiceLocation.ActivationException' occurred in GalaSoft.MvvmLight.Extras.dll but was not handled in user code
$exception {Microsoft.Practices.ServiceLocation.ActivationException: Type not found in cache: StackOverF.Services.IStorageService. at GalaSoft.MvvmLight.Ioc.SimpleIoc.DoGetService(Type serviceType, String key, Boolean cache) in c:\MvvmLight\Source\GalaSoft.MvvmLight\GalaSoft.MvvmLight.Extras (PCL)\Ioc\SimpleIoc.cs:line 537 at GalaSoft.MvvmLight.Ioc.SimpleIoc.GetService(Type serviceType) in c:\MvvmLight\Source\GalaSoft.MvvmLight\GalaSoft.MvvmLight.Extras (PCL)\Ioc\SimpleIoc.cs:line 789 at GalaSoft.MvvmLight.Ioc.SimpleIoc.MakeInstanceTClass in c:\MvvmLight\Source\GalaSoft.MvvmLight\GalaSoft.MvvmLight.Extras (PCL)\Ioc\SimpleIoc.cs:line 729} System.Exception {Microsoft.Practices.ServiceLocation.ActivationException}
Is there anything that you guys can tell me that maybe the blog author skipped over that I need to do? Maybe if enough rocks are thrown at this "boulder," it'll crack open...
Clarification
There are basically currently only two projects in my Visual Studio Solution. One is the Portable Class Library. The other is the WPF Application. In the very near future, once I get things working on the WPF side of the equation, I'll use the PCL in Xamarin to reuse the code in an Android project. However, the Android side is not part of my problem here. I'm having the above issue when only dealing with the WPF project.
Code (Last edited Feb 18, 2016)
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, located in WPF Project)
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, located in PCL Project)
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() {
}
}
}
It errors (WHILE DEBUGGING ONLY) on the return ServiceLocator.Current.GetInstance<IMainViewModel>();
line.
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>