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
where TOptions : class { private readonly IOptionsFactory _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
(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中显示
项目结构及运行效果如下图:
/yi-dong-ying-yong-kai-fa/prismshi-yong-optionsxuan-xiang-11718.html