坐不住喜单溜 发表于 2023-12-5 23:27:49

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< 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>项目结构及运行效果如下图:


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