Question

There is a way to reset application settings with Settings.Default.Reset()

Is there a way to reset only one property? Something like

Settings.Default.Properties["MyPropertyName"].Reset();
Was it helpful?

Solution 3

Found solution when reading .NET source code:

Settings.Default.PropertyValues["MyPropertyName"].SerializedValue = Settings.Default.Properties["MyPropertyName"].DefaultValue;
Settings.Default.PropertyValues["MyPropertyName"].Deserialized = false;

OTHER TIPS

You can use the Settings.Default.Properties["MyProperty"].DefaultValue to obtain the default value for the property, and set the property value to that.

It's the PropertyValue that's need to be set in combinaison of Deserialized (the order matter) :

public void ResetOneSetting(string propertyName)
{
    SettingsPropertyValue propertyToReset = Settings.Default.PropertyValues.OfType<SettingsPropertyValue>().FirstOrDefault(p => p.Name == propertyName);
    if (propertyToReset != null)
    {
        propertyToReset.PropertyValue = propertyToReset.Property.DefaultValue;
        propertyToReset.Deserialized = false;
    }
}

In my case (.NET Framework 4.6.1, with a System.Drawing.Color as setting), I also had to re-assign the value in Settings.Default, otherwise the change seemed to be ignored:

var propertyValue = Settings.Default.PropertyValues["myPropertyName"];

propertyValue.PropertyValue = propertyValue.Property.DefaultValue;
propertyValue.Deserialized = false;

Settings.Default["myPropertyName"] = propertyValue.PropertyValue;

I use the following code to reset a setting in my program. It takes advantage of reflection and allows you to pass a property directly instead of you manually writing out a properties name. It can be used like ResetToDefaultValue(TestSettings.Default, x => x.TextFieldStuff);

The advantage of this is that it does not all your settings are in Settings but some might be stored in different settings files.

//Way to use
//ResetToDefaultValue(TestSettings.Default, x => x.TextFieldStuff);
private static void ResetToDefaultValue<T1, T2>(T1 settings, Expression<Func<T1, T2>> property, bool saveOnReset = true)
{
    if (IsSameOrSubclass(typeof(ApplicationSettingsBase), settings.GetType()))
    {
        ApplicationSettingsBase s = settings as ApplicationSettingsBase;
        if (s != null)
        {
            MemberInfo member = GetMemberInfo(property);
            if (!s.PropertyValues[member.Name].UsingDefaultValue)
            {
                s.PropertyValues[member.Name].PropertyValue = s.PropertyValues[member.Name].Property.DefaultValue;
                s.PropertyValues[member.Name].Deserialized = false;
                s[member.Name] = s.PropertyValues[member.Name].PropertyValue; //Triggers the property changed
                if (saveOnReset)
                {
                    s.Save();
                }
            }
        }
    }
}

//Way to use
//GetMemberInfo((TestSettings testSettings) => testSettings.TextFieldStuff);
private static MemberInfo GetMemberInfo<T1, T2>(Expression<Func<T1, T2>> expression)
{
    if (IsSameOrSubclass(typeof(MemberExpression), expression.Body.GetType()))
    {
        MemberExpression member = (MemberExpression)expression.Body;
        return member.Member;
    }

    throw new ArgumentException(@"Expression is not a member access", nameof(expression));
}

private static bool IsSameOrSubclass(Type potentialBase, Type potentialDescendant)
{
    return potentialDescendant.IsSubclassOf(potentialBase)
           || potentialDescendant == potentialBase;
}

Or if you are using C# 7.1 or greater, you can use feature matching.

//Way to use
//ResetToDefaultValue(TestSettings.Default, x => x.TextFieldStuff);
private static void ResetToDefaultValue<T1, T2>(T1 settings, Expression<Func<T1, T2>> property, bool saveOnReset = true)
{
    //Requires C# >= 7.1
    if (settings is ApplicationSettingsBase s)
    {
        MemberInfo member = GetMemberInfo(property);
        if (!s.PropertyValues[member.Name].UsingDefaultValue)
        {
            s.PropertyValues[member.Name].PropertyValue = s.PropertyValues[member.Name].Property.DefaultValue;
            s.PropertyValues[member.Name].Deserialized = false;
            s[member.Name] = s.PropertyValues[member.Name].PropertyValue;
            if (saveOnReset)
            {
                s.Save();
            }
        }
    }
}

//Way to use
//GetMemberInfo((TestSettings testSettings) => testSettings.TextFieldStuff);
private static MemberInfo GetMemberInfo<T1, T2>(Expression<Func<T1, T2>> expression)
{
    //Requires C# >= 7.0
    if (expression.Body is MemberExpression member)
    {
        return member.Member;
    }

    throw new ArgumentException(@"Expression is not a member access", nameof(expression));
}

While I checked out the answers from @dalleria and @nikita, I run into the problem that the PropertyValue (SettingsPropertyValue) got defaulted unexpectely when I tried to get a deep copy of DefaultValue (SettingsProperty) or PropertyValue (SettingsPropertyValue) or any other same typed value.

So here is my short implementation of a deep copy function that is part of a class, so I apologize for not refactoring it to a extension or tool method.

private SettingsPropertyValue settingsPropertyValue; // (ex. Settings.Default.PropertyValues["anyPropertyName"])

private SettingsProperty settingsProperty 
            => settingsPropertyValue.Property;

/// <summary>
/// Create a deep copy of <paramref name="value"/>.
/// </summary>
/// <param name="value">
/// Should be a deserialized value (ex. <see cref="SettingsPropertyValue.PropertyValue"/>) 
/// or a serialized value (ex. <see cref="SettingsProperty.DefaultValue"/>).
/// </param>
/// <param name="isDeserialized">Indicates whether <paramref name="value"/> is deserialized or serialized.</param>
private PropertyType copyValue<PropertyType>(object value, bool isDeserialized)
{
    var temporaryPropertyValue = settingsPropertyValue.PropertyValue;
    settingsPropertyValue.PropertyValue = value;

    if (isDeserialized)
        // We have to reassign, otherwise PropertyValue/SerializedValue of SettingsPropertyValue may be defaulted
        settingsPropertyValue.SerializedValue = settingsPropertyValue.SerializedValue; 

    settingsPropertyValue.Deserialized = false;
    var propertyValue = (PropertyType)settingsPropertyValue.PropertyValue;
    settingsPropertyValue.PropertyValue = temporaryPropertyValue;
    return propertyValue;
}

You can then reset a single property of an instance of ApplicationSettings/SettingsBase with these lines:

SettingsBase settings; // (ex. Settings.Default)

public void SetOriginalFromDefault()
{
    object defaultValue = settingsProperty.DefaultValue;
    defaultValue = copyValue(defaultValue, false);
    // We want to set the new value. It also triggers the INotifyPropertyChanged of settings, if the instance is from type ApplicationSettings
    settings[settingsProperty.Name] = defaultValue;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top