Prism使用Options选项

  • Prism使用Options选项已关闭评论
  • 92 次浏览
  • A+
所属分类:.NET技术
摘要

Options是微软提供的选项模块,该模块依赖于容器使用。除了微软的IServiceCollection,当然也可以使用其它的依赖注入容器。本文演示如何在prism中使用Options。

Options是微软提供的选项模块,该模块依赖于容器使用。除了微软的IServiceCollection,当然也可以使用其它的依赖注入容器。本文演示如何在prism中使用Options。

创建应用项目

创建一个Avalonia应用(或其它类型应用),然后使用NuGet包管理器添加Prism.DryIoc.Avalonia包。创建Views和ViewModels文件夹,将MainWindow移动到Views文件夹中(注意修改namespace),在ViewModels文件夹中创建MainWindowViewModel,以便Prism自动绑定ViewModel。

public partial class App : PrismApplication {     public override void Initialize()     {         AvaloniaXamlLoader.Load(this);         base.Initialize();     }      protected override AvaloniaObject CreateShell()     {         return Container.Resolve<MainWindow>();     }      protected override void RegisterTypes(IContainerRegistry containerRegistry)     {         containerRegistry.Register<MainWindow>();     } } 

添加Options功能

  • 首先使用NuGet添加Microsoft.Extentions.Options和Microsoft.Extensions.Options.ConfigurationExtensions。使用json配置文件进行测试,因此再添加上Microsoft.Extensions.Configuration.Json及Microsoft.Extensions.Configuration.Binder。

  • 添加Options静态类,提供DefaultName:

public static class Options {     public static readonly string DefaultName = string.Empty;     internal const DynamicallyAccessedMemberTypes DynamicallyAccessedMembers =         DynamicallyAccessedMemberTypes.PublicParameterlessConstructor; } 
  • 由于UnnamedOptionsManager为内部类,无法直接使用,因此添加一个UnnamedOptionsManager类,实现IOptions<>接口,直接拷贝源码即可:
public class UnnamedOptionsManager<[DynamicallyAccessedMembers(Options.DynamicallyAccessedMembers)] TOptions> :     IOptions<TOptions>     where TOptions : class {     private readonly IOptionsFactory<TOptions> _factory;     private volatile object _syncObj;     private volatile TOptions _value;      public UnnamedOptionsManager(IOptionsFactory<TOptions> factory) => _factory = factory;      public TOptions Value     {         get         {             if (_value is TOptions value)                 return value;              lock (_syncObj ?? Interlocked.CompareExchange(ref _syncObj, new object(), null) ?? _syncObj)             {                 return _value ??= _factory.Create(Options.DefaultName);             }         }     } } 
  • 添加OptionsPrismExtensions扩展类,添加AddOptions扩展方法,将选项泛型接口、工厂、缓存注册到容器中。工厂注册为瞬时,其它注册为单例。客户端不需要添加IOptionsSnapshot,只添加IOptions<>和IOptionsMonitor<>即可,前者获取选项不会监听修改,后者可以监听选项修改:
public static class OptionsPrismExtensions {     public static IContainerExtension AddOptions(this IContainerExtension container)     {         ArgumentNullException.ThrowIfNull(container, nameof(container));          container.RegisterSingleton(typeof(IOptions<>), typeof(UnnamedOptionsManager<>));         container.RegisterSingleton(typeof(IOptionsMonitor<>), typeof(OptionsMonitor<>));         container.Register(typeof(IOptionsFactory<>), typeof(OptionsFactory<>));         container.RegisterSingleton(typeof(IOptionsMonitorCache<>), typeof(OptionsCache<>));         return container;     } } 
  • 添加OptionsConfigurationPrismExtensions扩展类,提供Configuration相关的扩展方法,可以直接将选项和配置Section进行绑定:
public static class OptionsConfigurationPrismExtensions {     public static IContainerExtension Configure<[DynamicallyAccessedMembers(         DynamicallyAccessedMemberTypes.All)] TOptions>(this IContainerExtension container,          IConfiguration config) where TOptions : class         => container.Configure<TOptions>(Options.DefaultName, config, _ => { });      public static IContainerExtension Configure<[DynamicallyAccessedMembers(         DynamicallyAccessedMemberTypes.All)] TOptions>(this IContainerExtension container,          string name, IConfiguration config, Action<BinderOptions> configureBinder)         where TOptions : class     {         ArgumentNullException.ThrowIfNull(container, nameof(container));         ArgumentNullException.ThrowIfNull(config, nameof(config));              container.AddOptions();         container.RegisterInstance<IOptionsChangeTokenSource<TOptions>>(             new ConfigurationChangeTokenSource<TOptions>(name, config));         container.RegisterInstance<IConfigureOptions<TOptions>>(             new NamedConfigureFromConfigurationOptions<TOptions>(name, config, configureBinder));              return container;     } } 

使用

  • 添加一个settings.json配置文件,设置属性复制到输出目录:如果较新则复制:
{   "Test": {     "Name": "louzi",     "Age": 18,     "Sex": "Male"   } } 
  • 添加Test对应的Option实体:
public class TestOption {     public string Name { get; set; }      public int Age { get; set; }      public Gender Sex { get; set; } }  public enum Gender {     Male,     Female } 
  • 创建IConfiguration并绑定到选项:
// App protected override IContainerExtension CreateContainerExtension() {     var container =  base.CreateContainerExtension();      IConfiguration config = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory())         .AddJsonFile("settings.json", optional: true, reloadOnChange: true).Build();     container.AddOptions().Configure<TestOption>(config.GetSection("Test"));      return container; } 
  • ViewModel中通过依赖注入获取选项:
public class MainWindowViewModel : BindableBase {     private string _name;     private int _age;     private Gender _sex;      public MainWindowViewModel(IOptions<TestOption> options)     {         var testOption = options.Value;         _name = testOption.Name;         _age = testOption.Age;         _sex = testOption.Sex;     }      public string Name { get => _name; set => SetProperty(ref _name, value); }      public int Age { get => _age; set => SetProperty(ref _age, value); }      public Gender Sex { get => _sex; set => SetProperty(ref _sex, value); } } 
  • View中显示
<Grid RowDefinitions="1*,1*,1*" ColumnDefinitions="1*,1*"> 	<TextBlock Text="Name: " TextAlignment="Right"/> 	<TextBlock Text="{Binding Name}" Grid.Column="1"/> 	<TextBlock Text="Age: " Grid.Row="1" TextAlignment="Right"/> 	<TextBlock Text="{Binding Age}" Grid.Row="1" Grid.Column="1"/> 	<TextBlock Text="Sex: " Grid.Row="2" TextAlignment="Right"/> 	<TextBlock Text="{Binding Sex}" Grid.Row="2" Grid.Column="1"/> </Grid> 

项目结构及运行效果如下图:
Prism使用Options选项