等效于WPF .NET 5、.NET 6或.Net核心中的用户设置/应用程序设置

rggaifut  于 2022-11-18  发布在  .NET
关注(0)|答案(7)|浏览(219)

对于使用.NET 5、.NET 6或.Net Core〉=3.0的WPF应用程序,保持用户设置的首选方式是什么?
.NET用户设置到哪里去了?
创建了WPF .Net Core 3.0项目(VS 2019 V16.3.1)现在我已经看到没有属性.设置部分了。[更新2022:在.NET 6中,它仍然是相同的]

在线搜索后,开始深入到Microsoft. Extensions. Configuration中。
除了臃肿的代码访问设置,现在更糟-〉没有保存?
User Configuration Settings in .NET Core
幸运或不幸的是,Microsoft.Extensions.Configuration的设计不支持保存。阅读更多Github问题Why there is no save in ConfigurationProvider?
对于使用.Net Core〉=3.0 / .NET5 / .NET6的WPF应用程序,保持用户设置的首选方法是什么?
在〈= .Net 4.8之前,它就像这样简单:

  • 将变量添加到属性。

  • 启动时读取变量

var culture = new CultureInfo(Properties.Settings.Default.LanguageSettings);

  • 当变量改变时-〉立即保存它

Properties.Settings.Default.LanguageSettings = selected.TwoLetterISOLanguageName; Properties.Settings.Default.Save();

jdg4fx2g

jdg4fx2g1#

您可以添加相同的旧的好的设置文件,例如通过右键单击属性-〉添加-〉新项目,并搜索“设置”。该文件可以在设置设计器中编辑,并像以前在.net框架项目中一样使用(ConfigurationManager,Settings.Default.Upgrade(),Settings.Default.保存等工作)。
将app.config文件添加到项目根文件夹中(同样通过Add -〉New Item),再次保存设置,编译项目,您将在输出文件夹中找到一个.dll.config文件。您现在可以像以前一样更改默认的app值。
使用Visual Studio 1.16.3.5和.net核心3.0 WPF项目进行测试。

dgenwo3n

dgenwo3n2#

正如你在文章中所指出的,Microsoft.Extensions.Configuration API是为你的应用设置的一次性应用,或者至少是只读的。如果你的主要目标是简单/快速/简单地保存用户设置,你可以自己做一些事情。将设置存储在ApplicationData文件夹中,类似于旧的API。

public class SettingsManager<T> where T : class
{
    private readonly string _filePath;

    public SettingsManager(string fileName)
    {
        _filePath = GetLocalFilePath(fileName);
    }

    private string GetLocalFilePath(string fileName)
    {
        string appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
        return Path.Combine(appData, fileName);
    }

    public T LoadSettings() =>
        File.Exists(_filePath) ?
        JsonConvert.DeserializeObject<T>(File.ReadAllText(_filePath)) :
        null;

    public void SaveSettings(T settings)
    {
        string json = JsonConvert.SerializeObject(settings);
        File.WriteAllText(_filePath, json);
    }
}

使用最基本UserSettings的演示

public class UserSettings
{
    public string Name { get; set; }
}

我不会提供一个完整的MVVM示例,但内存中仍有一个示例,ref _userSettings。一旦您加载设置,演示程序将覆盖其默认属性。当然,在生产环境中,您不会在启动时提供默认值。这只是出于说明的目的。

public partial class MainWindow : Window
{
    private readonly SettingsManager<UserSettings> _settingsManager;
    private UserSettings _userSettings;

    public MainWindow()
    {
        InitializeComponent();

        _userSettings = new UserSettings() { Name = "Funk" };
        _settingsManager = new SettingsManager<UserSettings>("UserSettings.json");
    }

    private void Button_FromMemory(object sender, RoutedEventArgs e)
    {
        Apply(_userSettings);
    }

    private void Button_LoadSettings(object sender, RoutedEventArgs e)
    {
        _userSettings = _settingsManager.LoadSettings();
        Apply(_userSettings);
    }

    private void Button_SaveSettings(object sender, RoutedEventArgs e)
    {
        _userSettings.Name = textBox.Text;
        _settingsManager.SaveSettings(_userSettings);
    }

    private void Apply(UserSettings userSettings)
    {
        textBox.Text = userSettings?.Name ?? "No settings found";
    }
}

XAML语言

<Window x:Class="WpfApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.Resources>
        <Style TargetType="Button">
            <Setter Property="Margin" Value="10"/>
        </Style> 
    </Window.Resources>
    <Grid Margin="10">
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <TextBox Grid.Row="0" x:Name="textBox" Width="150" HorizontalAlignment="Center" VerticalAlignment="Center"/>
        <Button Grid.Row="1" Click="Button_FromMemory">From Memory</Button>
        <Button Grid.Row="2" Click="Button_LoadSettings">Load Settings</Button>
        <Button Grid.Row="3" Click="Button_SaveSettings">Save Settings</Button>
    </Grid>
</Window>
bkkx9g8r

bkkx9g8r3#

您可以使用Nuget包System.Configuration.ConfigurationManager。它与.Net Standard 2.0兼容,因此应该可以在.Net Core应用程序中使用。
没有设计器来实现这个功能,但是除此之外,它的工作方式与.Net版本相同,并且您应该能够从Settings.Designer.cs复制代码。此外,您可以重写OnPropertyChanged,因此不需要调用Save
下面是一个示例,来自正在工作的.Net Standard项目:

public class WatchConfig: ApplicationSettingsBase
{
    static WatchConfig _defaultInstance = (WatchConfig)Synchronized(new WatchConfig());

    public static WatchConfig Default { get => _defaultInstance; }

    protected override void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        Save();
        base.OnPropertyChanged(sender, e);
    }

    [UserScopedSetting]
    [global::System.Configuration.DefaultSettingValueAttribute(
    @"<?xml    version=""1.0"" encoding=""utf-16""?>
    <ArrayOfString>
      <string>C:\temp</string>
     <string>..\otherdir</string>
     </ArrayOfString>")]
    public StringCollection Directories
    {
        get { return (StringCollection)this[nameof(Directories)]; }
        set { this[nameof(Directories)] = value; }
    }
}
km0tfn4u

km0tfn4u4#

用于Wpf网络核心
项目单击鼠标右键-〉添加新项-〉设置文件(常规)

用途

Settings1.Default.Height = this.Height;
Settings1.Default.Width = this.Width;

this.Height = Settings1.Default.Height;
this.Width = Settings1.Default.Width;

Settings1.Default.Save();

"设置1“创建文件名的位置

  • 示例 *

双击“Settings1.settings”文件并编辑

private void MainWindowRoot_SourceInitialized(object sender, EventArgs e)
{
    this.Top = Settings1.Default.Top;
    this.Left = Settings1.Default.Left;
    this.Height = Settings1.Default.Height;
    this.Width = Settings1.Default.Width;
    // Very quick and dirty - but it does the job
    if (Settings1.Default.Maximized)
    {
        WindowState = WindowState.Maximized;
    }
}

private void MainWindowRoot_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
    if (WindowState == WindowState.Maximized)
    {
        // Use the RestoreBounds as the current values will be 0, 0 and the size of the screen
        Settings1.Default.Top = RestoreBounds.Top;
        Settings1.Default.Left = RestoreBounds.Left;
        Settings1.Default.Height = RestoreBounds.Height;
        Settings1.Default.Width = RestoreBounds.Width;
        Settings1.Default.Maximized = true;
    }
    else
    {
        Settings1.Default.Top = this.Top;
        Settings1.Default.Left = this.Left;
        Settings1.Default.Height = this.Height;
        Settings1.Default.Width = this.Width;
        Settings1.Default.Maximized = false;
    }

    Settings1.Default.Save();
}
8oomwypt

8oomwypt5#

我对公认答案的改进被拒绝了,所以在这里作为单独的答案。

不需要任何nuget包,也不需要滚动自己的JSON等。

默认情况下,在创建新的.NET Core或.NET5/6项目时,设置部分会丢失,您必须手动添加它。
只需在解决方案中手动创建Properties文件夹。当您将新文件夹命名为Properties时,您会看到文件夹图标会略有变化。

右键单击此新的Properties文件夹并添加New Item
添加一个设置文件,并将建议名称从Settings1.settings重命名为Settings.settings,使其与旧项目中的名称相同

给你。设置已经恢复了。

您可以添加应用程序配置文件以获取输出目录中的.config文件

wko9yo5t

wko9yo5t6#

基于Funk的answer,这里有一个抽象的通用singleton风格的变体,它删除了一些关于SettingsManager的管理,并使创建和使用附加设置类尽可能简单:
键入的设置类:

//Use System.Text.Json attributes to control serialization and defaults
public class MySettings : SettingsManager<MySettings>
{
    public bool SomeBoolean { get; set; }
    public string MyText { get; set; }
}

用法:

//Loading and reading values
MySettings.Load();
var theText = MySettings.Instance.MyText;
var theBool = MySettings.Instance.SomeBoolean;

//Updating values
MySettings.Instance.MyText = "SomeNewText"
MySettings.Save();

正如您所看到的,要创建和使用设置的线的数量也是最少的,并且由于没有参数,因此更严格一些。
基类定义存储设置的位置,并且每个MySettings子类只允许一个设置文件-程序集和类名确定其位置。对于替换属性文件的目的,这就足够了。

using System;
using System.IO;
using System.Linq;
using System.Reflection;

public abstract class SettingsManager<T> where T : SettingsManager<T>, new()
{
    private static readonly string filePath = GetLocalFilePath($"{typeof(T).Name}.json");

    public static T Instance { get; private set; }

    private static string GetLocalFilePath(string fileName)
    {
        string appData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); 
        var companyName = Assembly.GetEntryAssembly().GetCustomAttributes<AssemblyCompanyAttribute>().FirstOrDefault();
        return Path.Combine(appData, companyName?.Company ?? Assembly.GetEntryAssembly().GetName().Name, fileName);
    }

    public static void Load()
    {
        if (File.Exists(filePath))
            Instance = System.Text.Json.JsonSerializer.Deserialize<T>(File.ReadAllText(filePath));
        else
            Instance = new T(); 
    }

    public static void Save()
    {
        string json = System.Text.Json.JsonSerializer.Serialize(Instance);
        Directory.CreateDirectory(Path.GetDirectoryName(filePath));
        File.WriteAllText(filePath, json);
    }
}

在禁用settings子类的构造函数和创建SettingsManager<T>.Instance而不使用Load()时可能会进行一些改进;这取决于您自己的用例。

sqougxex

sqougxex7#

只需双击项目中的Settings.settings文件。它仍然会像以前一样在设计器中打开。只是它不再列在“属性”窗口中。

相关问题