应用程序服务¶
应用程序服务(Application Services)提供了一种简洁、解耦的方式,让您可以在 ViewModel 和业务逻辑中处理窗口、对话框以及整个应用程序的外观设置。您无需直接引用窗口和对话框或访问系统功能,而是通过定义明确的服务接口来请求这些功能。服务负责处理平台相关的代码,而您的业务逻辑保持与平台无关。
以下代码片段演示了如何使用 IMessageBoxService 从 ViewModel 中显示消息框。
using Eremex.AvaloniaUI.Controls.ApplicationServices;
public class MyViewModel
{
public MyViewModel() { }
[RelayCommand]
private void ShowInformation()
{
// Access an IMessageBoxService and show a message box.
var result = Service<IMessageBoxService>()
.Show("Connection established", "Information", MessageBoxButtons.Ok, MessageBoxIcon.Information);
}
// Provides direct access to any service
protected static T Service<T>() where T : class
=> ApplicationServicesContext.GetRequiredService<T>();
}
Tip
有关如何在 ApplicationServicesContext 中注册内置服务的完整代码,请参阅使用 ApplicationServicesContext 和 SimpleServiceProvider 访问内置服务。
服务可以做什么?¶
窗口管理¶
- 在代码的任何位置获取活动窗口
- 自动为对话框设置所有者
用户交互¶
- 显示带有预定义按钮集的标准消息框
- 创建带有应用程序自定义按钮标题的选择对话框
- 显示由 ViewModel 驱动的模态对话框
- 显示绑定到 ViewModel 的非模态窗口
文件操作¶
- 使用系统文件对话框打开文件
- 使用系统对话框保存文件
- 同时支持同步和异步操作
外观和主题¶
- 获取可用的主题选项
- 在 UI 中创建主题选择器
可用服务¶
Eremex Controls 库包含以下服务,每个服务提供特定的功能。
用户交互服务¶
| 服务 | 说明 |
|---|---|
IMessageBoxService |
显示标准消息框,其固定按钮集由 MessageBoxButtons 枚举定义(Ok、Ok|Cancel、Yes|No|Cancel、Yes|No、Abort|Retry|Ignore 和 Retry|Cancel)。 |
IDialogService |
从 ViewModel 代码中显示对话框,使 ViewModel 无需引用任何窗口类型即可向用户提问。对话框由_对话框 ViewModel_ 驱动。您还可以实现一个 View 作为对话框的内容显示。该 View 通过应用于对话框 ViewModel 的 ViewLocatorAttribute 进行定位。 |
IChoiceDialogService |
显示带有任意按钮集的对话框,并返回所按按钮的结果。 |
IWindowService |
从 ViewModel 代码中显示非模态窗口,使 ViewModel 无需引用任何窗口类型即可打开窗口。模态对话框对应的服务是 IDialogService。 |
文件服务¶
| 服务 | 说明 |
|---|---|
IOpenFileDialogService |
以同步或异步模式从 ViewModel 代码中显示平台的 Open File 对话框。 |
ISaveFileDialogService |
以同步或异步模式从 ViewModel 代码中显示平台的 Save File 对话框。 |
基础设施服务¶
| 服务 | 说明 |
|---|---|
IWindowsManager |
跟踪应用程序的活动窗口。对话框服务使用 IWindowsManager 服务为新创建的对话框获取默认所有者。 |
IAppearanceService |
列出视觉主题设置并应用所选的主题变体。 |
使用服务¶
您可以使用 ApplicationServicesContext 和 SimpleServiceProvider 类来使用内置服务,也可以使用自定义 DI 容器。
使用 ApplicationServicesContext 和 SimpleServiceProvider 访问内置服务¶
在应用程序启动时(在 App 类中),将内置服务注册到 SimpleServiceProvider 和 ApplicationServicesContext。然后在 ViewModel 中创建一个便捷的 Service<T>() 辅助方法,通过 ApplicationServicesContext.GetRequiredService<T> 方法访问这些服务。
using Eremex.AvaloniaUI.Controls.ApplicationServices;
public abstract partial class ApplicationServicesPageViewModelBase : PageViewModelBase
{
// Provides direct access to any service
protected static T Service<T>() where T : class
=> ApplicationServicesContext.GetRequiredService<T>();
}
public partial class MyViewModel : ApplicationServicesPageViewModelBase
{
[RelayCommand]
private void ShowInformation()
{
// Access an IMessageBoxService and show a message box.
var result = Service<IMessageBoxService>()
.Show("Connection established", "Information", MessageBoxButtons.Ok, MessageBoxIcon.Information);
}
}
public class App : Application
{
public override void OnFrameworkInitializationCompleted()
{
RegisterApplicationServices();
//...
}
static void RegisterApplicationServices()
{
// Register built-in services.
var serviceProvider = new SimpleServiceProvider();
ApplicationServicesContext.RegisterApplicationServices(serviceProvider.AddSingleton);
ApplicationServicesContext.SetCurrent(serviceProvider);
}
}
SimpleServiceProvider 是 IServiceProvider 的最小实现,无需任何外部 NuGet 包。它是一个轻量级、线程安全的容器,适用于不需要完整 DI 容器的应用程序和测试。所有服务都是延迟创建的,并以单例形式存在(只创建一次,并在应用程序的整个生命周期内缓存)。实现了 IDisposable 的已创建实例由 Dispose 方法释放。
通过构造函数注入访问服务¶
需要时,您可以将应用程序服务直接传递给 ViewModel,然后在 ViewModel 中调用该服务的方法。
public partial class MyViewModel
{
private readonly IMessageBoxService messageBoxService;
public MyViewModel(IMessageBoxService messageBoxService)
{
this.messageBoxService = messageBoxService;
}
[RelayCommand]
private void ShowInformation()
{
var result = messageBoxService.Show("Connection established", "Information", MessageBoxButtons.Ok, MessageBoxIcon.Information);
}
}
自定义依赖注入容器支持¶
如果您使用外部 DI 容器,请将内置服务注册到该容器中,并将得到的提供程序设置为当前提供程序。
-
Microsoft.Extensions.DependencyInjection
var services = new ServiceCollection(); services.AddTransient<IDataService, DataService>(); ApplicationServicesContext.RegisterApplicationServices( (type, factory) => services.AddSingleton(type, sp => factory(sp)) ); var provider = services.BuildServiceProvider(); ApplicationServicesContext.SetCurrent(provider); -
Autofac
var services = new ServiceCollection(); services.AddTransient<IDataService, DataService>(); //... var builder = new ContainerBuilder(); builder.Populate(services); ApplicationServicesContext.RegisterApplicationServices( (type, factory) => builder .Register(c => factory(c.Resolve<IServiceProvider>())) .As(type) .SingleInstance() ); var container = builder.Build(); var serviceProvider = new AutofacServiceProvider(container); ApplicationServicesContext.SetCurrent(serviceProvider); -
自定义
IServiceProvider实现您可以自行实现
IServiceProvider,并将其传递给ApplicationServicesContext.SetCurrent。
* 本页面使用机器翻译技术翻译。