翼度科技»论坛 编程开发 .net 查看内容

Prism使用Options选项

6

主题

6

帖子

18

积分

新手上路

Rank: 1

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

创建一个Avalonia应用(或其它类型应用),然后使用NuGet包管理器添加Prism.DryIoc.Avalonia包。创建Views和ViewModels文件夹,将MainWindow移动到Views文件夹中(注意修改namespace),在ViewModels文件夹中创建MainWindowViewModel,以便Prism自动绑定ViewModel。
  1. public partial class App : PrismApplication
  2. {
  3.     public override void Initialize()
  4.     {
  5.         AvaloniaXamlLoader.Load(this);
  6.         base.Initialize();
  7.     }
  8.     protected override AvaloniaObject CreateShell()
  9.     {
  10.         return Container.Resolve<MainWindow>();
  11.     }
  12.     protected override void RegisterTypes(IContainerRegistry containerRegistry)
  13.     {
  14.         containerRegistry.Register<MainWindow>();
  15.     }
  16. }
复制代码
添加Options功能


  • 首先使用NuGet添加Microsoft.Extentions.Options和Microsoft.Extensions.Options.ConfigurationExtensions。使用json配置文件进行测试,因此再添加上Microsoft.Extensions.Configuration.Json及Microsoft.Extensions.Configuration.Binder。
  • 添加Options静态类,提供DefaultName:
  1. public static class Options
  2. {
  3.     public static readonly string DefaultName = string.Empty;
  4.     internal const DynamicallyAccessedMemberTypes DynamicallyAccessedMembers =
  5.         DynamicallyAccessedMemberTypes.PublicParameterlessConstructor;
  6. }
复制代码

  • 由于UnnamedOptionsManager为内部类,无法直接使用,因此添加一个UnnamedOptionsManager类,实现IOptions接口,直接拷贝源码即可:
  1. public class UnnamedOptionsManager<[DynamicallyAccessedMembers(Options.DynamicallyAccessedMembers)] TOptions> :
  2.     IOptions<TOptions>
  3.     where TOptions : class
  4. {
  5.     private readonly IOptionsFactory<TOptions> _factory;
  6.     private volatile object _syncObj;
  7.     private volatile TOptions _value;
  8.     public UnnamedOptionsManager(IOptionsFactory<TOptions> factory) => _factory = factory;
  9.     public TOptions Value
  10.     {
  11.         get
  12.         {
  13.             if (_value is TOptions value)
  14.                 return value;
  15.             lock (_syncObj ?? Interlocked.CompareExchange(ref _syncObj, new object(), null) ?? _syncObj)
  16.             {
  17.                 return _value ??= _factory.Create(Options.DefaultName);
  18.             }
  19.         }
  20.     }
  21. }
复制代码

  • 添加OptionsPrismExtensions扩展类,添加AddOptions扩展方法,将选项泛型接口、工厂、缓存注册到容器中。工厂注册为瞬时,其它注册为单例。客户端不需要添加IOptionsSnapshot,只添加IOptions和IOptionsMonitor即可,前者获取选项不会监听修改,后者可以监听选项修改:
  1. public static class OptionsPrismExtensions
  2. {
  3.     public static IContainerExtension AddOptions(this IContainerExtension container)
  4.     {
  5.         ArgumentNullException.ThrowIfNull(container, nameof(container));
  6.         container.RegisterSingleton(typeof(IOptions<>), typeof(UnnamedOptionsManager<>));
  7.         container.RegisterSingleton(typeof(IOptionsMonitor<>), typeof(OptionsMonitor<>));
  8.         container.Register(typeof(IOptionsFactory<>), typeof(OptionsFactory<>));
  9.         container.RegisterSingleton(typeof(IOptionsMonitorCache<>), typeof(OptionsCache<>));
  10.         return container;
  11.     }
  12. }
复制代码

  • 添加OptionsConfigurationPrismExtensions扩展类,提供Configuration相关的扩展方法,可以直接将选项和配置Section进行绑定:
  1. public static class OptionsConfigurationPrismExtensions
  2. {
  3.     public static IContainerExtension Configure<[DynamicallyAccessedMembers(
  4.         DynamicallyAccessedMemberTypes.All)] TOptions>(this IContainerExtension container,
  5.         IConfiguration config) where TOptions : class
  6.         => container.Configure<TOptions>(Options.DefaultName, config, _ => { });
  7.     public static IContainerExtension Configure<[DynamicallyAccessedMembers(
  8.         DynamicallyAccessedMemberTypes.All)] TOptions>(this IContainerExtension container,
  9.         string name, IConfiguration config, Action<BinderOptions> configureBinder)
  10.         where TOptions : class
  11.     {
  12.         ArgumentNullException.ThrowIfNull(container, nameof(container));
  13.         ArgumentNullException.ThrowIfNull(config, nameof(config));
  14.    
  15.         container.AddOptions();
  16.         container.RegisterInstance<IOptionsChangeTokenSource<TOptions>>(
  17.             new ConfigurationChangeTokenSource<TOptions>(name, config));
  18.         container.RegisterInstance<IConfigureOptions<TOptions>>(
  19.             new NamedConfigureFromConfigurationOptions<TOptions>(name, config, configureBinder));
  20.    
  21.         return container;
  22.     }
  23. }
复制代码
使用


  • 添加一个settings.json配置文件,设置属性复制到输出目录:如果较新则复制:
  1. {
  2.   "Test": {
  3.     "Name": "louzi",
  4.     "Age": 18,
  5.     "Sex": "Male"
  6.   }
  7. }
复制代码

  • 添加Test对应的Option实体:
  1. public class TestOption
  2. {
  3.     public string Name { get; set; }
  4.     public int Age { get; set; }
  5.     public Gender Sex { get; set; }
  6. }
  7. public enum Gender
  8. {
  9.     Male,
  10.     Female
  11. }
复制代码

  • 创建IConfiguration并绑定到选项:
  1. // App
  2. protected override IContainerExtension CreateContainerExtension()
  3. {
  4.     var container =  base.CreateContainerExtension();
  5.     IConfiguration config = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory())
  6.         .AddJsonFile("settings.json", optional: true, reloadOnChange: true).Build();
  7.     container.AddOptions().Configure<TestOption>(config.GetSection("Test"));
  8.     return container;
  9. }
复制代码

  • ViewModel中通过依赖注入获取选项:
  1. public class MainWindowViewModel : BindableBase
  2. {
  3.     private string _name;
  4.     private int _age;
  5.     private Gender _sex;
  6.     public MainWindowViewModel(IOptions<TestOption> options)
  7.     {
  8.         var testOption = options.Value;
  9.         _name = testOption.Name;
  10.         _age = testOption.Age;
  11.         _sex = testOption.Sex;
  12.     }
  13.     public string Name { get => _name; set => SetProperty(ref _name, value); }
  14.     public int Age { get => _age; set => SetProperty(ref _age, value); }
  15.     public Gender Sex { get => _sex; set => SetProperty(ref _sex, value); }
  16. }
复制代码

  • View中显示
  1. <Grid RowDefinitions="1*,1*,1*" ColumnDefinitions="1*,1*">
  2.         <TextBlock Text="Name: " TextAlignment="Right"/>
  3.         <TextBlock Text="{Binding Name}" Grid.Column="1"/>
  4.         <TextBlock Text="Age: " Grid.Row="1" TextAlignment="Right"/>
  5.         <TextBlock Text="{Binding Age}" Grid.Row="1" Grid.Column="1"/>
  6.         <TextBlock Text="Sex: " Grid.Row="2" TextAlignment="Right"/>
  7.         <TextBlock Text="{Binding Sex}" Grid.Row="2" Grid.Column="1"/>
  8. </Grid>
复制代码
项目结构及运行效果如下图:


来源:https://www.cnblogs.com/louzixl/archive/2023/12/05/17877961.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具