Been googling it for a while, but found nothing really good.
So, the thing is, in MVVM Cross
guides our solution (for mobile platforms) is separated on, as example, HelloWorld.Core
project and few platform specific projects, as example HelloWorld.Android.UI
.
You can see full tutorial here https://www.mvvmcross.com/documentation/tipcalc-tutorial/the-tip-calc-tutorial
And, the thing is, in our .Core
project we creating Services, ViewModels and we registering it in MVVM Cross provided IoC-container.
In example which provided by the MvvmCross documentation Service
implementation is really simple, just one function like that
public class CalculationService: ICalculationService
{
public double TipAmount(double subTotal, int generosity)
{
return subTotal * ((double)generosity)/100.0;
}
}
so we just go ahead, registering it in our App.cs
and then its fine to use in binded ViewModel
public class App: MvxApplication
{
public App()
{
Mvx.RegisterType<ICalculationService, CalculationService>();
Mvx.RegisterSingleton<IMvxAppStart>(new MvxAppStart<HomeViewModel>());
}
}
View model code :
public class TipViewModel : MvxViewModel
{
readonly ICalculation _calculation;
public TipViewModel(ICalculation calculation)
{
_calculation = calculation;
}
// ...
double _tip;
public double Tip
{
get {
return _tip;
}
set
{
_tip = value;
RaisePropertyChanged(() => Tip);
}
}
void Recalculate()
{
Tip = _calculation.TipAmount(SubTotal, Generosity);
}
}
But the thing is, when I started playing around with that, I decided, to, let say, code some simple local storage data scanner to find some specific files.
Simple code example:
public class SimpleDataScanner : IBaseDataScanner
{
private string _basePath { get; set; }
private List<string> _scanResult { get; set; }
public SimpleDataScanner()
{
_basePath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
_scanResult = new List<string>();
}
public List<string> BasicDataScan(string startPath = null)
{
string startFolder = _basePath;
if (startPath.Length > 0 && startPath.Length != null)
{
startFolder = Path.Combine(_basePath, startPath);
}
try
{
TreeScan(startFolder);
}
catch (Exception)
{
throw;
}
return _scanResult;
}
private void TreeScan(string path)
{
foreach (var file in Directory.GetFiles(path))
{
if (Path.HasExtension("pdf"))
{
_scanResult.Add(file);
}
}
foreach (string dir in Directory.GetDirectories(path))
{
TreeScan(dir);
}
}
}
And, as I found out, the problems are:
1) I can't use Android specific functions and properties in PCL
2) I can't use reference in my PCL Core
project to, lets say, some other Android
class lib project
So, I can't create working Service which means I can't register it in IoC-container and pass to ViewModel.
Whats the way of doing such things? Any tutorials? Or I getting whole idea wrong?
You need to implement the interface in your platform code, and register the concrete implementation against the interface in Setup.cs
inside your platform project. So in your case, IDataScanner
would exist inside your Core
project, while SimpleDataScanner
would live in the Android project.
Inside Setup.cs
, you'd register the concrete implementation like this:
protected override void InitializeFirstChance()
{
base.InitializeFirstChance();
Mvx.RegisterSingleton<IDataScanner>(() => new SimpleDataScanner());
}
Essentially, if the interface requires platform-specific or full .NET framework code to implement, those per-platform implementations live in the platforms and are registered in the platform setup. If both the interface and the implementation are shared within the Core
project, the dependency can be registered in App.cs
.