mirror of
https://github.com/Hofknecht/SystemTrayMenu.git
synced 2024-06-01 18:19:39 +12:00
[BUG] ConfigurationErrorsException: Failed to save settings (#120)
This commit is contained in:
parent
35011aeb57
commit
506e573cd5
250
Properties/CustomSettingsProvider.cs
Normal file
250
Properties/CustomSettingsProvider.cs
Normal file
|
@ -0,0 +1,250 @@
|
|||
// <copyright file="CustomSettingsProvider.cs" company="PlaceholderCompany">
|
||||
// Copyright (c) PlaceholderCompany. All rights reserved.
|
||||
// </copyright>
|
||||
|
||||
namespace SystemTrayMenu.Properties
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
internal class CustomSettingsProvider : SettingsProvider
|
||||
{
|
||||
private const string NameOf = "name";
|
||||
private const string SerializeAs = "serializeAs";
|
||||
private const string Config = "configuration";
|
||||
private const string UserSettings = "userSettings";
|
||||
private const string Setting = "setting";
|
||||
|
||||
private bool loaded;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CustomSettingsProvider"/> class.
|
||||
/// Loads the file into memory.
|
||||
/// </summary>
|
||||
public CustomSettingsProvider()
|
||||
{
|
||||
SettingsDictionary = new Dictionary<string, SettingStruct>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets override.
|
||||
/// </summary>
|
||||
public override string ApplicationName
|
||||
{
|
||||
get
|
||||
{
|
||||
return System.Reflection.Assembly.GetExecutingAssembly().ManifestModule.Name;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the setting key this is returning must set before the settings are used.
|
||||
/// e.g. <c>Properties.Settings.Default.SettingsKey = @"C:\temp\user.config";</c>.
|
||||
/// </summary>
|
||||
private string UserConfigPath
|
||||
{
|
||||
get
|
||||
{
|
||||
return Path.Combine(
|
||||
Path.Combine(
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
||||
$"SystemTrayMenu"),
|
||||
$"user-{Environment.MachineName}.config");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets in memory storage of the settings values.
|
||||
/// </summary>
|
||||
private Dictionary<string, SettingStruct> SettingsDictionary { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Override.
|
||||
/// </summary>
|
||||
/// <param name="name">name.</param>
|
||||
/// <param name="config">config.</param>
|
||||
public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
|
||||
{
|
||||
base.Initialize(ApplicationName, config);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Must override this, this is the bit that matches up the designer properties to the dictionary values.
|
||||
/// </summary>
|
||||
/// <param name="context">context.</param>
|
||||
/// <param name="collection">collection.</param>
|
||||
/// <returns>SettingsPropertyValueCollection.</returns>
|
||||
public override SettingsPropertyValueCollection GetPropertyValues(SettingsContext context, SettingsPropertyCollection collection)
|
||||
{
|
||||
// load the file
|
||||
if (!loaded)
|
||||
{
|
||||
loaded = true;
|
||||
LoadValuesFromFile();
|
||||
}
|
||||
|
||||
// collection that will be returned.
|
||||
SettingsPropertyValueCollection values = new SettingsPropertyValueCollection();
|
||||
|
||||
// itterate thought the properties we get from the designer, checking to see if the setting is in the dictionary
|
||||
foreach (SettingsProperty setting in collection)
|
||||
{
|
||||
SettingsPropertyValue value = new SettingsPropertyValue(setting);
|
||||
value.IsDirty = false;
|
||||
|
||||
// need the type of the value for the strong typing
|
||||
var t = Type.GetType(setting.PropertyType.FullName);
|
||||
|
||||
if (SettingsDictionary.ContainsKey(setting.Name))
|
||||
{
|
||||
value.SerializedValue = SettingsDictionary[setting.Name].Value;
|
||||
value.PropertyValue = Convert.ChangeType(SettingsDictionary[setting.Name].Value, t, CultureInfo.InvariantCulture);
|
||||
}
|
||||
else
|
||||
{
|
||||
// use defaults in the case where there are no settings yet
|
||||
value.SerializedValue = setting.DefaultValue;
|
||||
value.PropertyValue = Convert.ChangeType(setting.DefaultValue, t, CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
values.Add(value);
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Must override this, this is the bit that does the saving to file. Called when Settings.Save() is called.
|
||||
/// </summary>
|
||||
/// <param name="context">context.</param>
|
||||
/// <param name="collection">collection.</param>
|
||||
public override void SetPropertyValues(SettingsContext context, SettingsPropertyValueCollection collection)
|
||||
{
|
||||
// grab the values from the collection parameter and update the values in our dictionary.
|
||||
foreach (SettingsPropertyValue value in collection)
|
||||
{
|
||||
var setting = new SettingStruct()
|
||||
{
|
||||
Value = value.PropertyValue == null ? string.Empty : value.PropertyValue.ToString(),
|
||||
Name = value.Name,
|
||||
SerializeAs = value.Property.SerializeAs.ToString(),
|
||||
};
|
||||
|
||||
if (!SettingsDictionary.ContainsKey(value.Name))
|
||||
{
|
||||
SettingsDictionary.Add(value.Name, setting);
|
||||
}
|
||||
else
|
||||
{
|
||||
SettingsDictionary[value.Name] = setting;
|
||||
}
|
||||
}
|
||||
|
||||
// now that our local dictionary is up-to-date, save it to disk.
|
||||
SaveValuesToFile();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads the values of the file into memory.
|
||||
/// </summary>
|
||||
private void LoadValuesFromFile()
|
||||
{
|
||||
if (!File.Exists(UserConfigPath))
|
||||
{
|
||||
// if the config file is not where it's supposed to be create a new one.
|
||||
CreateEmptyConfig();
|
||||
}
|
||||
|
||||
// load the xml
|
||||
var configXml = XDocument.Load(UserConfigPath);
|
||||
|
||||
// get all of the <setting name="..." serializeAs="..."> elements.
|
||||
var settingElements = configXml.Element(Config).Element(UserSettings).Element(typeof(Properties.Settings).FullName).Elements(Setting);
|
||||
|
||||
// iterate through, adding them to the dictionary, (checking for nulls, xml no likey nulls)
|
||||
// using "String" as default serializeAs...just in case, no real good reason.
|
||||
foreach (var element in settingElements)
|
||||
{
|
||||
var newSetting = new SettingStruct()
|
||||
{
|
||||
Name = element.Attribute(NameOf) == null ? string.Empty : element.Attribute(NameOf).Value,
|
||||
SerializeAs = element.Attribute(SerializeAs) == null ? "String" : element.Attribute(SerializeAs).Value,
|
||||
Value = element.Value ?? string.Empty,
|
||||
};
|
||||
SettingsDictionary.Add(element.Attribute(NameOf).Value, newSetting);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an empty user.config file...looks like the one MS creates.
|
||||
/// This could be overkill a simple key/value pairing would probably do.
|
||||
/// </summary>
|
||||
private void CreateEmptyConfig()
|
||||
{
|
||||
var doc = new XDocument();
|
||||
var declaration = new XDeclaration("1.0", "utf-8", "true");
|
||||
var config = new XElement(Config);
|
||||
var userSettings = new XElement(UserSettings);
|
||||
var group = new XElement(typeof(Properties.Settings).FullName);
|
||||
userSettings.Add(group);
|
||||
config.Add(userSettings);
|
||||
doc.Add(config);
|
||||
doc.Declaration = declaration;
|
||||
doc.Save(UserConfigPath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves the in memory dictionary to the user config file.
|
||||
/// </summary>
|
||||
private void SaveValuesToFile()
|
||||
{
|
||||
// load the current xml from the file.
|
||||
var import = XDocument.Load(UserConfigPath);
|
||||
|
||||
// get the settings group (e.g. <Company.Project.Desktop.Settings>)
|
||||
var settingsSection = import.Element(Config).Element(UserSettings).Element(typeof(Properties.Settings).FullName);
|
||||
|
||||
// iterate though the dictionary, either updating the value or adding the new setting.
|
||||
foreach (var entry in SettingsDictionary)
|
||||
{
|
||||
var setting = settingsSection.Elements().FirstOrDefault(e => e.Attribute(NameOf).Value == entry.Key);
|
||||
if (setting == null)
|
||||
{
|
||||
// this can happen if a new setting is added via the .settings designer.
|
||||
var newSetting = new XElement(Setting);
|
||||
newSetting.Add(new XAttribute(NameOf, entry.Value.Name));
|
||||
newSetting.Add(new XAttribute(SerializeAs, entry.Value.SerializeAs));
|
||||
newSetting.Value = entry.Value.Value ?? string.Empty;
|
||||
settingsSection.Add(newSetting);
|
||||
}
|
||||
else
|
||||
{
|
||||
// update the value if it exists.
|
||||
setting.Value = entry.Value.Value ?? string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
import.Save(UserConfigPath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper struct.
|
||||
/// </summary>
|
||||
internal struct SettingStruct
|
||||
{
|
||||
internal string Name;
|
||||
internal string SerializeAs;
|
||||
internal string Value;
|
||||
}
|
||||
}
|
||||
}
|
5
Properties/Settings.Designer.cs
generated
5
Properties/Settings.Designer.cs
generated
|
@ -24,6 +24,7 @@ namespace SystemTrayMenu.Properties {
|
|||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Configuration.SettingsProviderAttribute(typeof(CustomSettingsProvider))]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("")]
|
||||
public string CurrentCultureInfoName {
|
||||
|
@ -36,6 +37,7 @@ namespace SystemTrayMenu.Properties {
|
|||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Configuration.SettingsProviderAttribute(typeof(CustomSettingsProvider))]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("")]
|
||||
public string PathDirectory {
|
||||
|
@ -48,6 +50,7 @@ namespace SystemTrayMenu.Properties {
|
|||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Configuration.SettingsProviderAttribute(typeof(CustomSettingsProvider))]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("False")]
|
||||
public bool IsAutostartActivated {
|
||||
|
@ -60,6 +63,7 @@ namespace SystemTrayMenu.Properties {
|
|||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Configuration.SettingsProviderAttribute(typeof(CustomSettingsProvider))]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("Ctrl+Alt+Apps")]
|
||||
public string HotKey {
|
||||
|
@ -72,6 +76,7 @@ namespace SystemTrayMenu.Properties {
|
|||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Configuration.SettingsProviderAttribute(typeof(CustomSettingsProvider))]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("False")]
|
||||
public bool IsUpgraded {
|
||||
|
|
|
@ -2,19 +2,19 @@
|
|||
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="SystemTrayMenu.Properties" GeneratedClassName="Settings">
|
||||
<Profiles />
|
||||
<Settings>
|
||||
<Setting Name="CurrentCultureInfoName" Type="System.String" Scope="User">
|
||||
<Setting Name="CurrentCultureInfoName" Provider="CustomSettingsProvider" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
<Setting Name="PathDirectory" Type="System.String" Scope="User">
|
||||
<Setting Name="PathDirectory" Provider="CustomSettingsProvider" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
<Setting Name="IsAutostartActivated" Type="System.Boolean" Scope="User">
|
||||
<Setting Name="IsAutostartActivated" Provider="CustomSettingsProvider" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
<Setting Name="HotKey" Type="System.String" Scope="User">
|
||||
<Setting Name="HotKey" Provider="CustomSettingsProvider" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)">Ctrl+Alt+Apps</Value>
|
||||
</Setting>
|
||||
<Setting Name="IsUpgraded" Type="System.Boolean" Scope="User">
|
||||
<Setting Name="IsUpgraded" Provider="CustomSettingsProvider" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
</Settings>
|
||||
|
|
|
@ -71,8 +71,6 @@ namespace SystemTrayMenu.Utilities
|
|||
return icon;
|
||||
}
|
||||
|
||||
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Reliability", "CA2008:Do not create tasks without passing a TaskScheduler", Justification = "todo")]
|
||||
public static Icon GetFolderIconSTA(
|
||||
string directoryPath,
|
||||
|
|
Loading…
Reference in a new issue