我知道这个问题已在 2 年前提出,但我可能有一个与您的要求相匹配的解决方案。
在过去的几个月里,我一直在使用 Xamarin 和 WPF 开发应用程序,并使用 Microsoft.Extensions.DependencyInjection 包将构造函数依赖注入添加到我的视图模型中,就像 ASP.NET 控制器一样。这意味着我可以有类似的东西:
public class MainViewModel : ViewModelBase
{
private readonly INavigationService _navigationService;
private readonly ILocalDatabase _database;
public MainViewModel(INavigationService navigationService, ILocalDatabase database)
{
_navigationService = navigationService;
_database = database;
}
}
为了实现这种过程,我使用IServiceCollection 添加服务并使用IServiceProvider 检索注册的服务。
要记住的重要一点是,IServiceCollection 是您将注册依赖项的容器。然后在构建此容器时,您将获得一个IServiceProvider,它将允许您检索服务。
为此,我通常会创建一个Bootstrapper 类来配置服务并初始化应用程序的主页。
基本实现
此示例演示如何将依赖项注入 Xamarin 页面。对于任何其他类,该过程保持不变。 (ViewModel 或其他类)
在您的项目中创建一个名为 Bootstrapper 的简单类,并初始化 IServiceCollection 和 IServiceProvider 私有字段。
public class Bootstrapper
{
private readonly Application _app;
private IServiceCollection _services;
private IServiceProvider _serviceProvider;
public Bootstrapper(Application app)
{
_app = app;
}
public void Start()
{
ConfigureServices();
}
private void ConfigureServices()
{
_services = new ServiceCollection();
// TODO: add services here
_serviceProvider = _services.BuildServiceProvider();
}
}
在ConfigureServices() 方法中,我们只是创建了一个新的ServiceCollection,我们将在其中添加我们的服务。 (见https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.dependencyinjection.servicecollection?view=dotnet-plat-ext-3.1)
添加服务后,我们将构建服务提供者,以便我们检索之前注册的服务。
然后在您的App 类构造函数中,创建一个新的Bootstrapper 实例并调用start 方法来初始化应用程序。
public partial class App : Application
{
public App()
{
InitializeComponent();
var bootstrapper = new Bootstrapper(this);
bootstrapper.Start();
}
...
}
通过这段代码,您已经设置了服务容器,但我们仍然需要初始化应用程序的MainPage。返回引导程序的 Start() 方法并创建所需主页的新实例。
public class Bootstrapper
{
...
public void Start()
{
ConfigureServices();
// Real magic happens here
var mainPageInstance = ActivatorUtilities.CreateInstance<MainPage>(_serviceProvider);
_app.MainPage = new NavigationPage(mainPageInstance);
}
}
这里我们使用ActivatorUtilities.CreateInstance<TInstance>() 方法来创建一个新的MainPage 实例。我们将_serviceProvider 作为参数,因为ActivatorUtilities.CreateInstance() 方法将负责创建您的实例并将所需的服务注入您的对象。
请注意,这是 ASP.NET Core 使用构造函数依赖注入实例化控制器的方法。
要对此进行测试,请创建一个简单的服务并尝试将其注入您的 MainPage 构造函数:
public interface IMySimpleService
{
void WriteMessage(string message);
}
public class MySimpleService : IMySimpleService
{
public void WriteMessage(string message)
{
Debug.WriteLine(message);
}
}
然后在Bootstrapper类的ConfigureServices()方法中注册:
private void ConfigureServices()
{
_services = new ServiceCollection();
_services.AddSingleton<IMySimpleService, MySimpleService>();
_serviceProvider = _services.BuildServiceProvider();
}
最后,转到您的MainPage.xaml.cs,注入IMySimpleService 并调用WriteMessage() 方法。
public partial class MainPage : ContentPage
{
public MainPage(IMySimpleService mySimpleService)
{
mySimpleService.WriteMessage("Hello world!");
}
}
到此,您已成功注册服务并将其注入您的页面。
构造函数注入的真正魔力是使用ActivatorUtilities.CreateInstance<T>() 方法通过传递服务提供者来实现的。该方法实际上会检查您的构造函数的参数并尝试通过尝试从您给他的IServiceProvider 中获取它们来解决依赖关系。
奖励:注册平台特定服务
这很好,对吧?借助ActivatorUtilities.CreateInstance<T>() 方法,您可以将服务注入任何类,但有时您还需要注册一些特定于平台的服务(Android 或 iOS)。
用前面的方法是不可能注册特定平台的服务的,因为IServiceCollection是在Bootstrapper类中初始化的。不用担心,解决方法非常简单。
您只需要将IServiceCollection 初始化提取到特定于平台的代码。只需在您的 Android 项目的 MainActivity.cs 和您的 iOS 项目的 AppDelegate 上初始化服务集合,然后将其传递给您的 App 类,该类会将其转发给 Bootstrapper:
MainActivity.cs (Android)
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
protected override void OnCreate(Bundle savedInstanceState)
{
...
var serviceCollection = new ServiceCollection();
// TODO: add platform specific services here.
var application = new App(serviceCollection);
LoadApplication(application);
}
...
}
AppDelegate.cs (iOS)
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init();
var serviceCollection = new ServiceCollection();
// TODO: add platform specific services here.
var application = new App(serviceCollection);
LoadApplication(application);
return base.FinishedLaunching(app, options);
}
}
App.xaml.cs(通用)
public partial class App : Application
{
public App(IServiceCollection services)
{
InitializeComponent();
var bootstrapper = new Bootstrapper(this, services);
bootstrapper.Start();
}
...
}
Bootstrapper.cs(通用)
public class Bootstrapper
{
private readonly Application _app;
private readonly IServiceCollection _services;
private IServiceProvider _serviceProvider;
public Bootstrapper(Application app, IServiceCollection services)
{
_app = app;
_services = services;
}
public void Start()
{
ConfigureServices();
var mainPageInstance = ActivatorUtilities.CreateInstance<MainPage>(_serviceProvider);
_app.MainPage = new NavigationPage(mainPageInstance);
}
private void ConfigureServices()
{
// TODO: add services here.
_serviceCollection.AddSingleton<IMySimpleService, MySimpleService>();
_serviceProvider = _services.BuildServiceProvider();
}
}
仅此而已,您现在可以注册特定于平台的服务并将接口轻松地注入您的页面/视图模型/类中。