You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何处理.NET MAUI MVVM应用的全局可持久化设置?

最优实现方案:单例配置服务 + 依赖注入

针对你的需求,最适合的方案是创建一个单例模式的配置服务,结合.NET MAUI的依赖注入体系来实现配置的全局共享、持久化和实时更新。以下是具体的分步实现:


1. 定义可通知的配置模型

首先创建配置实体类,实现INotifyPropertyChanged接口,确保配置修改后能自动通知所有绑定的UI和视图模型:

using System.ComponentModel;
using System.Runtime.CompilerServices;

public class AppConfig : INotifyPropertyChanged
{
    private string _apiBaseUrl;
    private bool _autoSyncEnabled;
    private int _syncIntervalMinutes;

    public string ApiBaseUrl
    {
        get => _apiBaseUrl;
        set => SetField(ref _apiBaseUrl, value);
    }

    public bool AutoSyncEnabled
    {
        get => _autoSyncEnabled;
        set => SetField(ref _autoSyncEnabled, value);
    }

    public int SyncIntervalMinutes
    {
        get => _syncIntervalMinutes;
        set => SetField(ref _syncIntervalMinutes, value);
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    protected bool SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
    {
        if (EqualityComparer<T>.Default.Equals(field, value)) return false;
        field = value;
        OnPropertyChanged(propertyName);
        return true;
    }
}

2. 实现配置服务(单例)

创建一个负责XML读写、配置管理的服务,用单例模式保证全局唯一实例:

using System.Xml.Serialization;

public interface IAppConfigService
{
    AppConfig CurrentConfig { get; }
    void LoadDefaultConfig();
    void SaveConfig();
}

public class AppConfigService : IAppConfigService
{
    private readonly AppConfig _currentConfig = new AppConfig();
    private readonly string _configPath;

    public AppConfig CurrentConfig => _currentConfig;

    public AppConfigService()
    {
        // 配置文件存储到应用专属数据目录(跨平台兼容)
        _configPath = Path.Combine(FileSystem.AppDataDirectory, "app_settings.xml");
    }

    public void LoadDefaultConfig()
    {
        if (File.Exists(_configPath))
        {
            try
            {
                // 从XML加载配置到现有实例(保持引用不变,保证通知生效)
                var serializer = new XmlSerializer(typeof(AppConfig));
                using var reader = new StreamReader(_configPath);
                var loadedConfig = serializer.Deserialize(reader) as AppConfig;

                if (loadedConfig != null)
                {
                    _currentConfig.ApiBaseUrl = loadedConfig.ApiBaseUrl;
                    _currentConfig.AutoSyncEnabled = loadedConfig.AutoSyncEnabled;
                    _currentConfig.SyncIntervalMinutes = loadedConfig.SyncIntervalMinutes;
                }
            }
            catch
            {
                // 加载失败时设置默认值
                SetDefaults();
            }
        }
        else
        {
            // 文件不存在时初始化默认值
            SetDefaults();
        }
    }

    public void SaveConfig()
    {
        try
        {
            var serializer = new XmlSerializer(typeof(AppConfig));
            using var writer = new StreamWriter(_configPath);
            serializer.Serialize(writer, _currentConfig);
        }
        catch
        {
            // 处理保存失败逻辑(如弹窗提示)
        }
    }

    private void SetDefaults()
    {
        _currentConfig.ApiBaseUrl = "https://api.example.com/v1";
        _currentConfig.AutoSyncEnabled = true;
        _currentConfig.SyncIntervalMinutes = 30;
    }
}

3. 注册服务并启动加载配置

在MauiProgram.cs中将配置服务注册为单例,确保全局只有一个实例:

var builder = MauiApp.CreateBuilder();
builder
    .UseMauiApp<App>()
    .ConfigureFonts(fonts =>
    {
        fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
    });

// 注册单例配置服务
builder.Services.AddSingleton<IAppConfigService, AppConfigService>();

return builder.Build();

然后在App.xaml.cs的启动方法中加载默认配置:

protected override void OnStart()
{
    var configService = Services.GetRequiredService<IAppConfigService>();
    configService.LoadDefaultConfig();
}

4. 设置页面的视图模型实现

在设置页面的ViewModel中注入配置服务,直接绑定配置实体,修改后调用保存方法:

public class SettingsViewModel : INotifyPropertyChanged
{
    private readonly IAppConfigService _configService;

    public AppConfig CurrentConfig => _configService.CurrentConfig;
    public ICommand SaveSettingsCommand { get; }

    public SettingsViewModel(IAppConfigService configService)
    {
        _configService = configService;
        SaveSettingsCommand = new Command(() => _configService.SaveConfig());
    }

    // INotifyPropertyChanged实现(如果需要额外通知逻辑)
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

设置页面XAML绑定示例:

<ContentPage.BindingContext>
    <viewmodels:SettingsViewModel />
</ContentPage.BindingContext>

<StackLayout Padding="20">
    <Entry Placeholder="API地址" Text="{Binding CurrentConfig.ApiBaseUrl}" />
    <Switch IsToggled="{Binding CurrentConfig.AutoSyncEnabled}" />
    <Entry Placeholder="同步间隔(分钟)" Text="{Binding CurrentConfig.SyncIntervalMinutes, Mode=TwoWay}" />
    <Button Text="保存设置" Command="{Binding SaveSettingsCommand}" />
</StackLayout>

5. 其他页面调用配置

在任意页面的ViewModel中注入配置服务,直接读取实时生效的配置值:

public class HomeViewModel : INotifyPropertyChanged
{
    private readonly IAppConfigService _configService;
    private string _syncStatus;

    public string SyncStatus
    {
        get => _syncStatus;
        set => SetField(ref _syncStatus, value);
    }

    public HomeViewModel(IAppConfigService configService)
    {
        _configService = configService;
        CheckSyncStatus();
    }

    private void CheckSyncStatus()
    {
        if (_configService.CurrentConfig.AutoSyncEnabled)
        {
            SyncStatus = $"自动同步已开启,间隔{_configService.CurrentConfig.SyncIntervalMinutes}分钟";
        }
        else
        {
            SyncStatus = "自动同步已关闭";
        }
    }

    // INotifyPropertyChanged基础实现
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
    protected bool SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
    {
        if (EqualityComparer<T>.Default.Equals(field, value)) return false;
        field = value;
        OnPropertyChanged(propertyName);
        return true;
    }
}

方案优势

  • 全局共享:单例服务保证所有页面使用同一个配置实例,修改后实时生效
  • MVVM友好:依赖注入实现解耦,便于单元测试和代码维护
  • 自动通知:配置实体实现INotifyPropertyChanged,UI和ViewModel能自动感知变化
  • 持久化可靠:配置存储在应用专属目录,跨平台兼容,读写异常有容错处理

内容的提问来源于stack exchange,提问作者user1366062

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 00:35:15