Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Equivalent to UserSettings / ApplicationSettings in WPF .NET 5, .NET 6 or .Net Core

What is the prefered way for persisting user settings for WPF applications with .NET 5, .NET 6 or .Net Core >=3.0?
Where are the .NET user settings gone?

Created WPF .Net Core 3.0 Project (VS2019 V16.3.1) Now I have seen there is no Properties.Settings section anymore. [Update 2022: With .NET 6 it is still the same]

SolutionExplorer

After online search, started to dive into Microsoft.Extensions.Configuration.

Beside the bloated code to access the settings, now even worse -> No save?
User Configuration Settings in .NET Core

Fortunately or unfortunately the Microsoft.Extensions.Configuration does not support saving by design. Read more in this Github issue Why there is no save in ConfigurationProvider?


What is the prefered (and easy/fast/simple) way for persisting user settings for WPF applications with .Net Core >=3.0 / .NET5 / .NET6?
Before <= .Net 4.8 it was as easy as:
  • add the variables to the Properties. User Settings

  • Read the variables at startup
    var culture = new CultureInfo(Properties.Settings.Default.LanguageSettings);

  • when a variable changes -> immediately save it
    Properties.Settings.Default.LanguageSettings = selected.TwoLetterISOLanguageName; Properties.Settings.Default.Save();

like image 607
MarkusEgle Avatar asked Jul 02 '19 07:07

MarkusEgle


People also ask

Does WPF support .NET 6?

The . NET Upgrade Assistant is a command-line tool that can assist with upgrading . NET Framework WPF apps to . NET 6.

Does WPF support .NET 5?

It has support for all kinds of . NET applications, including the Windows desktop platforms such as WPF, Windows Forms, and WinUI 3.0.

Can I use WPF with .NET core?

No. A WPF application targeting . NET Framework cannot reference a . NET Core project.


2 Answers

enter image description here

You can add the same old good settings file e.g. via the right click on the Properties -> Add -> New Item and search for the "Settings". The file can be edited in the settings designer and used as in the .net framework projects before (ConfigurationManager, Settings.Default.Upgrade(), Settings.Default.Save, etc. works).

Add also the app.config file to the project root folder (the same way via the Add -> New Item), save the settings once again, compile the project and you will find a .dll.config file in the output folder. You can change now default app values as before.

Tested with Visual Studio 1.16.3.5 and a .net core 3.0 WPF project.

like image 192
Alexander Zwitbaum Avatar answered Oct 02 '22 19:10

Alexander Zwitbaum


As pointed out in the posts you referenced, the Microsoft.Extensions.Configuration API is meant as a one time set up for your app, or at the very least to be read-only. If you're main goal is to persist user settings easy/fast/simple, you could roll something up yourself. Storing the settings in the ApplicationData folder, in resemblance to the old 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);
    }
}

A demo using the most basic of UserSettings

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

I'm not going to provide a full MVVM example, still we'd have an instance in memory, ref _userSettings. Once you load settings, the demo will have its default properties overridden. In production, of course, you wouldn't provide default values on start up. It's just for the purpose of illustration.

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>
like image 39
Funk Avatar answered Oct 02 '22 20:10

Funk