ソリューション エクスプローラーでプロジェクトのプロパティを開き、そこにある[設定]ペインで追加できます。
設定にはスコープという項目がありますが、これは次のように使い分けます。
スコープ | 用途 | プログラムによる書き換え | 保存場所 |
---|---|---|---|
アプリケーション (Application) | アプリケーション単位 | 不可 | 実行ファイルのフォルダ\AppName.exe.config |
ユーザー (User) | ユーザー単位 | 可能 | %LOCALAPPDATA%\Namespace\folder\Version\user.config |
ユーザー スコープの実際の保存場所は、System.Configurationを参照に追加した上で
System.Configuration.Configuration config = System.Configuration.ConfigurationManager.OpenExeConfiguration( System.Configuration.ConfigurationUserLevel.PerUserRoamingAndLocal); string filePath = config.FilePath;
とすることで確認できます。ConfigurationManager.OpenExeConfiguration メソッド (ConfigurationUserLevel) (System.Configuration) | MSDN
設定デザイナの一覧に表示されない型も、コードを記述することで使用できます。簡単には設定デザイナで適当な型で作成し、Settings.settingsをテキスト エディタで開きます。そしてそこでSetting要素のType属性を、希望する型に書き替えます。たとえばList<int>としたいならば、
<Setting Name="Setting" Type="System.Collections.Generic.List<int>" Scope="User">
のようにします。このときType属性に指定する型名は、名前空間も含めた完全修飾名とします。c# - How to save a List<string> on Settings.Default? - Stack Overflow
このように型としてコレクションを指定すると、構成ファイルではXMLで記録されます。
A | B
のように複数の値をビットフラグとして指定するには、その値はA, B
のようにカンマ区切りで指定します。
次のいずれかの書式のプロパティから取得できます。
global::Namespace.Properties.Settings.Default.Name
global::Namespace.Properties.Settings.Default["Name"]
SettingsPropertyクラスを介して取得できます。SettingsProperty.DefaultValue プロパティ (System.Configuration) | Microsoft Learn
string settingValue = (string)Settings.Default.Properties[ "SettingName" ].DefaultValue;
文字列の配列はStringCollectionクラスによりXML形式で格納されるため、既定値を取得するにはこれを構文解析します。
string settingValue = (string)Settings.Default.Properties[ "SettingName" ].DefaultValue; System.Xml.XmlDocument document = new System.Xml.XmlDocument(); document.LoadXml( settingValue ); foreach( System.Xml.XmlElement element in document.DocumentElement ) { string data = element.InnerText; }
このStringCollectionを利用すると、これをシリアル化するときにSystem.XmlSerializers.DLLが存在しないために、FileNotFoundExceptionが投げられます。これに対処するには代わりにStringクラスを用いるか、この例外を無視します。c# - FileNotFoundException in ApplicationSettingsBase - Stack Overflow
バージョンアップの影響などで無効な値が取得される可能性を考慮するならば、アプリケーション設定の取得時に値の検証を行います。それにはプロジェクトのプロパティにある設定デザイナ (Settings designer) で、[コードの表示]をクリックします。C# で設定を使用する | MSDN
するとSettings.csというファイル名で、次のようなSettingクラスが表示されます。
// このクラスでは設定クラスでの特定のイベントを処理できます: // SettingChanging イベントは、設定値が変更される前に発生します。 // PropertyChanged イベントは、設定値が変更された後に発生します。 // SettingsLoaded イベントは、設定値が読み込まれた後に発生します。 // SettingsSaving イベントは、設定値が保存される前に発生します。 internal sealed partial class Settings { public Settings() { // 設定の保存と変更のイベントハンドラを追加するには、以下の行のコメントを解除します: // // this.SettingChanging += this.SettingChangingEventHandler; // // this.SettingsSaving += this.SettingsSavingEventHandler; // } private void SettingChangingEventHandler(object sender, System.Configuration.SettingChangingEventArgs e) { // SettingChangingEvent イベントを処理するコードをここに追加してください。 } private void SettingsSavingEventHandler(object sender, System.ComponentModel.CancelEventArgs e) { // SettingsSaving イベントを処理するコードをここに追加してください。 } }
アプリケーション設定の読み込み時に処理するには、ここでSettingsLoadedイベントのハンドラを定義します。
internal sealed partial class Settings { public Settings() { SettingsLoaded += SettingsLoadedEventHandler; } private void SettingsLoadedEventHandler( object sender, System.Configuration.SettingsLoadedEventArgs e ) { // 値を検証する if( this.settingValue < 1.0 ) { // 既定値を設定する。直接キャストできないため、文字列を介して解析する this.settingValue = Double.Parse( (string)Settings.Default.Properties[ "SettingName" ].DefaultValue ); } } }
アプリケーション設定はアプリケーションのバージョンごとに異なるフォルダに保存されるため、通常ではバージョンアップ時に設定は引き継がれません。もし設定を引き継ぐようにしたいならば、ApplicationSettingsBaseのUpgrade()メソッドを呼び出します。前バージョンの設定を取得する - .NET Tips
Properties.Settings.Default.Upgrade();ApplicationSettingsBase.Upgrade メソッド (System.Configuration) | MSDN
またバージョンアップしたとき、初回の起動時にのみ設定を引き継ぐようにするには、更新したことを示すフラグをアプリケーション設定に記録しておきます。アプリケーション設定の Upgrade について - MSDN フォーラム
global::Namespace.Properties.Settings.Default.Name = 123;
SettingsPropertyCollection.Remove()でSettingsPropertyCollectionから削除できますが、ApplicationSettingsBase.Save()で保存するときにはそれが反映されず、削除前の値が保存されます。また既定値から変更せずに保存したときはその設定項目自体が書き込まれませんが、既定値を設定して保存すると、その値が保存されます。
よってXMLファイルに書き込まれた項目自体を削除するには、そのファイル自体を編集する必要があります。
Properties.Settings.Default.Save()を呼ぶことで保存できます。
public override void Save()ApplicationSettingsBase.Save メソッド (System.Configuration) | Microsoft Learn
ただし設定値に何も書き込んでおらず、保存する情報がなければ保存されません。
設定値が変更されていることを示すSettingsPropertyValue.IsDirtyは、値の型がstringやDateTime、それにint、float、realといったプリミティブ型ではない場合には、PropertyValueからアクセスされた時点で変更されたと見なされます。Remarks - SettingsPropertyValue.IsDirty Property (System.Configuration) | Microsoft Learn
イベント | 発生タイミング |
---|---|
SettingChanging | 値が変更される前。Reload()やReset()では発生しない |
PropertyChanged | 値が変更された後。Reload()やReset()で復元されたときにも発生する |
これらのイベントはApplicationSettingsBase.Item[]を介して値が設定されるときに発生するため、同一の値が設定されることで、実際には変更されていなくても発生します。
SettingChangingEventArgs.Cancelをfalseとすることで、変更を取り消せます。
保存場所や保存方法を変更するには、SettingsProviderを継承したクラスを作成し、それをSettingsクラスにSettingsProviderAttributeで指定します。
独自に定義したクラスは、プロパティ ウィンドウを表示した状態で設定デザイナで設定項目を選択し、[Provider]でクラス名を指定することでも適用できます。しかしこの方法では設定項目ごとに独自定義のクラスが呼ばれるため、Settingsクラスで指定するようにします。
class CustomSettingsProvider : SettingsProvider { private struct Setting { public string name; public string value; public SettingsSerializeAs serializeAs; } private readonly string userConfigPath; private Dictionary<string, Setting> settingsDictionary = null; public override string ApplicationName { get { System.Reflection.Assembly assembly = typeof(Program).Assembly; System.Reflection.AssemblyName assemblyName = assembly.GetName(); return assemblyName.Name; } set { } } public CustomSettingsProvider() { this.userConfigPath = @"C:\user.config"; } public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config) { base.Initialize(ApplicationName, config); } public override SettingsPropertyValueCollection GetPropertyValues(SettingsContext context, SettingsPropertyCollection collection) { if (this.settingsDictionary == null) { this.settingsDictionary = LoadSettingValues(this.userConfigPath); } SettingsPropertyValueCollection propertyValues = new SettingsPropertyValueCollection(); foreach (SettingsProperty property in collection) { SettingsPropertyValue propertyValue = new SettingsPropertyValue(property); object value; if (this.settingsDictionary.ContainsKey(property.Name)) { value = this.settingsDictionary[property.Name].value; } else { value = property.DefaultValue; } propertyValue.SerializedValue = value; if (value != null) { string text = value.ToString(); if (property.SerializeAs == SettingsSerializeAs.String) { System.ComponentModel.TypeConverter typeConverter = System.ComponentModel.TypeDescriptor.GetConverter(property.PropertyType); propertyValue.PropertyValue = typeConverter.ConvertFromString(text); } else if (property.SerializeAs == SettingsSerializeAs.Xml) { using (System.IO.StringReader stringReader = new System.IO.StringReader(text)) using (System.Xml.XmlReader xmlReader = System.Xml.XmlReader.Create(stringReader)) { System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(property.PropertyType); propertyValue.PropertyValue = serializer.Deserialize(xmlReader); } } else { throw new NotImplementedException(); } } propertyValue.IsDirty = false; propertyValues.Add(propertyValue); } return propertyValues; } public override void SetPropertyValues(SettingsContext context, SettingsPropertyValueCollection collection) { foreach (SettingsPropertyValue propertyValue in collection) { if (!propertyValue.IsDirty) continue; if (!propertyValue.Property.Attributes.Contains(typeof(UserScopedSettingAttribute))) continue; Setting setting = new Setting() { name = propertyValue.Name, value = propertyValue.SerializedValue.ToString(), serializeAs = propertyValue.Property.SerializeAs }; this.settingsDictionary[propertyValue.Name] = setting; } SaveSettingValues(this.userConfigPath, this.settingsDictionary); } private static Dictionary<string, Setting> LoadSettingValues(string path) { Dictionary<string, Setting> dictionary = new Dictionary<string, Setting>(); if (!System.IO.File.Exists(path)) return dictionary; // 指定のパスから読み込む using (System.Xml.XmlReader reader = System.Xml.XmlReader.Create(path)) { while (reader.ReadToFollowing("setting")) { string name = reader.GetAttribute("name"); string serializeAs = reader.GetAttribute("serializeAs"); string value = reader.ReadElementContentAsString(); if (String.IsNullOrEmpty(name)) continue; Setting setting = new Setting() { name = name, value = value, serializeAs = SettingsSerializeAs.String }; SettingsSerializeAs settingsSerializeAs; if (Enum.TryParse(serializeAs, out settingsSerializeAs)) { setting.serializeAs = settingsSerializeAs; } if (!dictionary.ContainsKey(setting.name)) { dictionary.Add(setting.name, setting); } } } return dictionary; } private static void SaveSettingValues(string path, Dictionary<string, Setting> dictionary) { System.Xml.XmlWriterSettings settings = new System.Xml.XmlWriterSettings(); settings.Indent = true; // 指定のパスに書き込む using (System.Xml.XmlWriter writer = System.Xml.XmlWriter.Create(path, settings)) { writer.WriteStartElement("configuration"); writer.WriteStartElement("userSettings"); writer.WriteStartElement(typeof(Properties.Settings).FullName); foreach (Setting setting in dictionary.Values) { writer.WriteStartElement("setting"); writer.WriteAttributeString("name", setting.name); writer.WriteAttributeString("serializeAs", setting.serializeAs.ToString()); writer.WriteString(setting.value ?? String.Empty); writer.WriteEndElement(); } writer.WriteEndElement(); writer.WriteEndElement(); writer.WriteEndElement(); } } }SettingsProvider Class (System.Configuration) | Microsoft Learn
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "*.0.0.0")] [global::System.Configuration.SettingsProviderAttribute(typeof(CustomSettingsProvider))] internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {SettingsProviderAttribute Class (System.Configuration) | Microsoft Learn
設定デザイナで編集すると追加の記述は削除されるため、その度に修正が必要です。
ファイル | 作成時機 | |
---|---|---|
プロジェクトのフォルダ\App.config | 構成ファイル | プロジェクトの作成時 |
プロジェクトのフォルダ\Properties\Settings.settings | ||
実行ファイルのフォルダ\AppName.exe.config | プロジェクトのビルド時 | |
%LOCALAPPDATA%\Namespace\folder\Version\user.config | Properties.Settings.Default.Save() 呼び出し時 |
設定デザイナでの編集はApp.configに反映され、その内容はビルド時にAppName.exe.configにコピーされます。
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" > <section name="WindowsFormsApplication1.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" /> </sectionGroup> <sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" > <section name="WindowsFormsApplication1.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" /> </sectionGroup> </configSections> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6" /> </startup> <userSettings> <WindowsFormsApplication1.Properties.Settings> <setting name="location" serializeAs="String"> <value>10, 20</value> </setting> <setting name="text" serializeAs="String"> <value>Form1</value> </setting> </WindowsFormsApplication1.Properties.Settings> </userSettings> <applicationSettings> <WindowsFormsApplication1.Properties.Settings> <setting name="sample" serializeAs="String"> <value>123</value> </setting> </WindowsFormsApplication1.Properties.Settings> </applicationSettings> </configuration>
内容 | |
---|---|
configuration | すべての構成ファイルのルート要素 |
configSections | 構成セクションの名前空間の定義 (sectionGroup) と構成セクションの宣言 (section) |
内容 | |
---|---|
startup | アプリケーションを実行するのに必要な、共通言語ランタイムのバージョンを示す |
supportedRuntime | アプリケーションがサポートする共通言語ランタイムのバージョン。オプションで.NET Frameworkのバージョン
|
内容 | |
---|---|
userSettings | 現在のユーザー固有のsetting要素 |
applicationSettings | アプリケーション康祐のsetting要素 |
この構成ファイルに誤りがあると、「認識されない構成セクション userSettings です。 (C:\\***\\user.config line 3)」としてConfigurationErrorsExceptionが投げられることがあります。この場合は、このファイルを一度削除してみます。