Windowsフォームアプリケーションにアプリケーション設定を保存するにはどうすればよいですか?


582

私が達成したいことは非常に簡単です。情報を読み取るためのパスを使用するWindowsフォーム(.NET 3.5)アプリケーションがあります。このパスは、ユーザーが提供するオプションフォームを使用して変更できます。

次に、パスの値を後で使用できるようにファイルに保存します。これは、このファイルに保存されている多くの設定の1つです。このファイルは、アプリケーションフォルダーに直接配置されます。

3つのオプションが利用できることを理解しています。

  • ConfigurationSettingsファイル(appname.exe.config)
  • レジストリ
  • カスタムXMLファイル

.NET構成ファイルは、値を保存して戻すことは想定されていません。レジストリに関しては、なるべく遠ざけたいと思います。

これは、構成設定を保存するためにカスタムXMLファイルを使用する必要があることを意味しますか?

もしそうなら、私はそのコード例を見たいと思います(C#)。

私はこの問題について他の議論を見てきましたが、それでも私にはわかりません。


これは.NET WinFormsアプリケーションですか?その場合、どのバージョンの.NETを開発していますか?
ポートマン

1
はい、これは.NET Frameworkバージョン3.5のWinFormsアプリケーションです。
煽ら

1
パスワードまたは秘密の値を保存する必要がありますか?暗号化
Kiquenet、2015

回答:


593

Visual Studioを使用する場合、永続化可能な設定を取得するのは非常に簡単です。ソリューションエクスプローラーでプロジェクトを右クリックし、[プロパティ]を選択します。[設定]タブを選択し、設定が存在しない場合はハイパーリンクをクリックします。

[設定]タブを使用して、アプリケーション設定を作成します。Visual Studioは、ApplicationSettingsBaseから継承さ れたシングルトンクラスを含むファイルSettings.settingsを作成します。コードからこのクラスにアクセスして、アプリケーション設定を読み書きできます。Settings.Designer.settingsSettings

Properties.Settings.Default["SomeProperty"] = "Some Value";
Properties.Settings.Default.Save(); // Saves settings in application configuration file

この手法は、コンソール、Windowsフォーム、およびその他のプロジェクトタイプの両方に適用できます。

設定のスコーププロパティを設定する必要があることに注意してください。Applicationスコープを選択した場合、Settings.Default。<your property>は読み取り専用になります。

リファレンス:方法:C#を使用して実行時にユーザー設定を書き込む -Microsoft Docs


2
ソリューションがある場合、これはソリューション全体または各プロジェクトに適用されますか?
franko_camron 2011年

8
@ 4:ここに.NET 4.0 WinAppプロジェクトがあり、SomePropertyは読み取り専用ではありません。Settings.Default.SomeProperty = 'value'; Settings.Default.Save();魅力のように動作します。それともユーザー設定があるからですか?
doekman 2012年

4
@Four:設定をユーザーからアプリケーションスコープに変更してファイルを保存すると、生成されたコードでセッターが消えたのがわかりました。これは、クライアントプロファイル4.0でも発生します...
doekman '17

3
@ 4:素晴らしいリンクですが、Settings.Default.Save()何もしないというあなたの声明は間違っています。@akuが答えで述べているように、app-scope設定は読み取り専用です。保存はそれらに対して無効です。そのカスタムPortableSettingsProviderを使用して、ユーザースコープ設定を、ユーザーのAppDataフォルダーではなく、exeがある場所にあるapp.configに保存します。いいえ、一般的には良くありませんが、開発中はコンパイルからコンパイルまで同じ設定を使用するために使用します(コンパイルしない場合、コンパイルごとに新しい一意のユーザーフォルダーに移動します)。
ミノー2012

7
現在のところ、.NET 3.5では、Settings.Default.SomePropertyを使用して値を割り当て、強力な型キャストを取得できるようです。また、他の人の時間を節約する(これを理解するにはしばらく時間をかけてください)には、Properties.Settings.Defaultと入力するか、YourProjectNameSpace.Settingsを使用してファイルの先頭に追加する必要があります。「設定」だけでは定義/見つかりません。
eselk 2013年

95

実行可能ファイルと同じディレクトリ内のファイルに保存することを計画している場合は、JSON形式を使用する優れたソリューションを次に示します

using System;
using System.IO;
using System.Web.Script.Serialization;

namespace MiscConsole
{
    class Program
    {
        static void Main(string[] args)
        {
            MySettings settings = MySettings.Load();
            Console.WriteLine("Current value of 'myInteger': " + settings.myInteger);
            Console.WriteLine("Incrementing 'myInteger'...");
            settings.myInteger++;
            Console.WriteLine("Saving settings...");
            settings.Save();
            Console.WriteLine("Done.");
            Console.ReadKey();
        }

        class MySettings : AppSettings<MySettings>
        {
            public string myString = "Hello World";
            public int myInteger = 1;
        }
    }

    public class AppSettings<T> where T : new()
    {
        private const string DEFAULT_FILENAME = "settings.json";

        public void Save(string fileName = DEFAULT_FILENAME)
        {
            File.WriteAllText(fileName, (new JavaScriptSerializer()).Serialize(this));
        }

        public static void Save(T pSettings, string fileName = DEFAULT_FILENAME)
        {
            File.WriteAllText(fileName, (new JavaScriptSerializer()).Serialize(pSettings));
        }

        public static T Load(string fileName = DEFAULT_FILENAME)
        {
            T t = new T();
            if(File.Exists(fileName))
                t = (new JavaScriptSerializer()).Deserialize<T>(File.ReadAllText(fileName));
            return t;
        }
    }
}

はい、別のディレクトリに保存する場合は、DEFAULT_FILENAMEを絶対パスに変更します。レジストリに保存しない場合は、ファイルをアプリケーションと同じディレクトリまたはサブディレクトリに保存するのが最も一般的だと思います。
Trevor

ああ、おそらくより良いオプションは、設定ファイルをユーザーのappdataフォルダーに保存することです。
Trevor

1
変更する必要はありません。DEFAULT_FILENAME呼び出すだけsettings.Save(theFileToSaveTo)です。すべて大文字でDEFAULT_FILENAMEあるため、定数と見なされます。読み書き可能なプロパティが必要な場合は、プロパティを作成し、コンストラクターでに設定しDEFAULT_FILENAMEます。次に、デフォルトの引数値をにしてnull、これをテストし、プロパティをデフォルト値として使用します。それはもう少しタイピングですが、より標準的なインターフェースを提供します。
ジェシーチザム

10
System.Web.Extensions.dllまだ参照していない場合は、参照する必要があります。
TEK 2016年

9
この回答に基づいてライブラリ全体を作成し、多くの改良を加えてnugetで使用できるようにしました:github.com/Nucs/JsonSettings
NucS

67

レジストリは立ち入り禁止です。アプリケーションを使用するユーザーがレジストリに書き込むための十分な権限を持っているかどうかはわかりません。

このapp.configファイルを使用して、アプリケーションレベルの設定(アプリケーションを使用する各ユーザーに共通)を保存できます。

ユーザー固有の設定をXMLファイルに保存します。このファイルは、分離ストレージまたはSpecialFolder.ApplicationDataディレクトリに保存されます。

その次に、.NET 2.0以降では、値をapp.configファイルに保存して戻すことができます。


8
ただし、ログイン/ユーザーごとの設定が必要な場合は、レジストリを使用してください。
thenonhacker 2009年

19
レジストリはポータブルではない
Kb。

10
@thenonhacker:または、Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)を使用します
Kenny Mann

4
ユーザー・レジストリーに書き込むことができます(多くのプログラムがそこに情報を書き込み、ユーザー許可は問題になりません)。設定を使用するよりもレジストリを使用する利点は、同じフォルダを共有する複数のアプリケーション(たとえば、セットアッププログラムとアプリケーションプログラム)がある場合、同じ設定を共有しないことです。
Kesty

3
レジストリの主な欠点は、設定を他のPCにエクスポート/コピーするのが難しい方法です。しかし、「アプリケーションを使用するユーザーがレジストリに書き込むための十分な権限を持っているかどうかわからない」という意見には同意しません-HKEY_CURRENT_USERでは、常に書き込み権限を持っています。拒否することはできますが、現在のユーザー(すべての可能なTEMPフォルダーなど)がファイルシステムにアクセスできない場合もあります。
i486

20

このApplicationSettingsクラスは、app.configファイルへの設定の保存をサポートしていません。これは仕様によるものです。適切に保護されたユーザーアカウント(Vista UACなど)で実行されるアプリケーションには、プログラムのインストールフォルダーへの書き込みアクセス権がありません。

ConfigurationManagerクラスとシステムを戦うことができます。ただし、簡単な回避策は、設定デザイナーに移動して、設定のスコープをユーザーに変更することです。それが困難な場合(たとえば、設定がすべてのユーザーに関連する場合)、オプションの機能を別のプログラムに配置して、特権の昇格のプロンプトを要求できるようにする必要があります。または設定を使用して見送ります。


最後の文章を詳しく教えていただけますか?app.configを作成するか、すべてのユーザーのホームフォラーを通過する別のアプリケーションを作成し、user.configを探してこれらを編集するための昇格を要求しますか?
CannibalSmith

2
別のプログラムでは、昇格を要求するマニフェストが必要です。Googleの「asinvoker requireadministrator」で適切な構文を見つける。user.configの編集は実用的でも、必要でもありません。
ハンスパッサント

18

registry / configurationSettings / XML引数はまだ非常にアクティブに見えます。テクノロジーが進歩するにつれて、私はそれらすべてを使用しましたが、私のお気に入りは、Threedのシステム分離ストレージを組み合わせたものに基づいています。

次のサンプルでは、​​プロパティという名前のオブジェクトを分離ストレージ内のファイルに保存できます。といった:

AppSettings.Save(myobject, "Prop1,Prop2", "myFile.jsn");

プロパティは以下を使用して回復できます:

AppSettings.Load(myobject, "myFile.jsn");

これは単なるサンプルであり、ベストプラクティスを示唆するものではありません。

internal static class AppSettings
{
    internal static void Save(object src, string targ, string fileName)
    {
        Dictionary<string, object> items = new Dictionary<string, object>();
        Type type = src.GetType();

        string[] paramList = targ.Split(new char[] { ',' });
        foreach (string paramName in paramList)
            items.Add(paramName, type.GetProperty(paramName.Trim()).GetValue(src, null));

        try
        {
            // GetUserStoreForApplication doesn't work - can't identify.
            // application unless published by ClickOnce or Silverlight
            IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForAssembly();
            using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(fileName, FileMode.Create, storage))
            using (StreamWriter writer = new StreamWriter(stream))
            {
                writer.Write((new JavaScriptSerializer()).Serialize(items));
            }

        }
        catch (Exception) { }   // If fails - just don't use preferences
    }

    internal static void Load(object tar, string fileName)
    {
        Dictionary<string, object> items = new Dictionary<string, object>();
        Type type = tar.GetType();

        try
        {
            // GetUserStoreForApplication doesn't work - can't identify
            // application unless published by ClickOnce or Silverlight
            IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForAssembly();
            using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(fileName, FileMode.Open, storage))
            using (StreamReader reader = new StreamReader(stream))
            {
                items = (new JavaScriptSerializer()).Deserialize<Dictionary<string, object>>(reader.ReadToEnd());
            }
        }
        catch (Exception) { return; }   // If fails - just don't use preferences.

        foreach (KeyValuePair<string, object> obj in items)
        {
            try
            {
                tar.GetType().GetProperty(obj.Key).SetValue(tar, obj.Value, null);
            }
            catch (Exception) { }
        }
    }
}

1
またはさらに良い; DataContractJsonSerializerを使用
Boczek

16

このために作成したライブラリを共有したいと思いました。これは小さなライブラリですが、.settingsファイルを大幅に改善(IMHO)したものです。

ライブラリはJot(GitHub)と呼ばれます。これは私が書いたコードプロジェクトの古い記事です。

これを使用して、ウィンドウのサイズと位置を追跡する方法は次のとおりです。

public MainWindow()
{
    InitializeComponent();

    _stateTracker.Configure(this)
        .IdentifyAs("MyMainWindow")
        .AddProperties(nameof(Height), nameof(Width), nameof(Left), nameof(Top), nameof(WindowState))
        .RegisterPersistTrigger(nameof(Closed))
        .Apply();
}

.settingsファイルと比較した場合の利点:コードが大幅に減り、各プロパティについて一だけ言及する必要があるため、エラーが発生しにくくなります。

設定ファイルでは、各プロパティを5回記述する必要があります。1回はプロパティを明示的に作成したときで、もう1回はコードで値を前後にコピーします。

ストレージ、シリアル化などは完全に構成可能です。ターゲットオブジェクトがIoCコンテナによって作成されると、[フックアップ] []して、解決するすべてのオブジェクトに追跡を自動的に適用できるため、プロパティを永続化するために必要なのは[Trackable]をたたくだけです。その上の属性。

高度な設定が可能で、次の設定を行うことができます。-データが永続化されてグローバルに適用されるか、追跡対象の各オブジェクトに適用されるとき-シリアル化の方法-データの保存場所(ファイル、データベース、オンライン、分離ストレージ、レジストリ)-適用をキャンセルできるルール/プロパティの永続化データ

私を信じて、ライブラリは一流です!


14

簡単な方法は、設定データオブジェクトを使用し、アプリケーションの名前を付けてXMLファイルとしてローカルフォルダーに保存し、起動時にそれを読み戻すことです。

フォームの位置とサイズを保存する例を次に示します。

設定データオブジェクトは強く型付けされており、使いやすいです:

[Serializable()]
public class CConfigDO
{
    private System.Drawing.Point m_oStartPos;
    private System.Drawing.Size m_oStartSize;

    public System.Drawing.Point StartPos
    {
        get { return m_oStartPos; }
        set { m_oStartPos = value; }
    }

    public System.Drawing.Size StartSize
    {
        get { return m_oStartSize; }
        set { m_oStartSize = value; }
    }
}

保存と読み込みのためのマネージャークラス:

public class CConfigMng
{
    private string m_sConfigFileName = System.IO.Path.GetFileNameWithoutExtension(System.Windows.Forms.Application.ExecutablePath) + ".xml";
    private CConfigDO m_oConfig = new CConfigDO();

    public CConfigDO Config
    {
        get { return m_oConfig; }
        set { m_oConfig = value; }
    }

    // Load configuration file
    public void LoadConfig()
    {
        if (System.IO.File.Exists(m_sConfigFileName))
        {
            System.IO.StreamReader srReader = System.IO.File.OpenText(m_sConfigFileName);
            Type tType = m_oConfig.GetType();
            System.Xml.Serialization.XmlSerializer xsSerializer = new System.Xml.Serialization.XmlSerializer(tType);
            object oData = xsSerializer.Deserialize(srReader);
            m_oConfig = (CConfigDO)oData;
            srReader.Close();
        }
    }

    // Save configuration file
    public void SaveConfig()
    {
        System.IO.StreamWriter swWriter = System.IO.File.CreateText(m_sConfigFileName);
        Type tType = m_oConfig.GetType();
        if (tType.IsSerializable)
        {
            System.Xml.Serialization.XmlSerializer xsSerializer = new System.Xml.Serialization.XmlSerializer(tType);
            xsSerializer.Serialize(swWriter, m_oConfig);
            swWriter.Close();
        }
    }
}

これで、インスタンスを作成し、フォームのloadイベントとcloseイベントで使用できます。

    private CConfigMng oConfigMng = new CConfigMng();

    private void Form1_Load(object sender, EventArgs e)
    {
        // Load configuration
        oConfigMng.LoadConfig();
        if (oConfigMng.Config.StartPos.X != 0 || oConfigMng.Config.StartPos.Y != 0)
        {
            Location = oConfigMng.Config.StartPos;
            Size = oConfigMng.Config.StartSize;
        }
    }

    private void Form1_FormClosed(object sender, FormClosedEventArgs e)
    {
        // Save configuration
        oConfigMng.Config.StartPos = Location;
        oConfigMng.Config.StartSize = Size;
        oConfigMng.SaveConfig();
    }

また、生成されたXMLファイルも読み取り可能です。

<?xml version="1.0" encoding="utf-8"?>
<CConfigDO xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <StartPos>
    <X>70</X>
    <Y>278</Y>
  </StartPos>
  <StartSize>
    <Width>253</Width>
    <Height>229</Height>
  </StartSize>
</CConfigDO>

1
私はこれを開発でうまく機能させていますが、アプリケーションをデプロイするとき、平均的なユーザーはc:\program files\my applicationフォルダーにアクセスできないため、設定を保存するとエラーがスローされます。代わりにxmlファイルをAppDataに保存することを検討していますが、このアプローチはうまくいったように見えるので、この問題を回避する明白な方法があるかどうか疑問に思いました。
フィリップストラトフォード2017年

@PhilipStratford通常のファイルなので、どこにでも保存できます。書き込み権限のある場所を見つけてください。
Dieter Meemken

@PhilipStratford AppDataフォルダーはオプションの可能性があります。カイトで言及されているように、C#で%AppData%のパスを取得するを参照してください。
Dieter Meemken

おかげで、私はすでにこれを実装しており、xmlファイルをAppDateフォルダーに保存しています。私はあなたがそれを機能させたと思っていたので、あなたの例に従ってアプリケーションのフォルダにそれを保存する簡単な方法があるかどうか疑問に思いました。心配する必要はありません。とにかくAppDataフォルダーの方が適切な場所です。
Philip Stratford


5

その他のオプションでは、カスタムXMLファイルを使用する代わりに、よりユーザーフレンドリーなファイル形式(JSONまたはYAMLファイル)を使用できます。

  • .NET 4.0ダイナミックを使用する場合、このライブラリは本当に使いやすいです(シリアライズ、デシリアライズ、ネストされたオブジェクトのサポート、必要に応じた出力の順序付け+複数の設定を1つにマージ)JsonConfig(使用法はApplicationSettingsBaseと同等です)
  • .NET YAML構成ライブラリの場合... JsonConfigほど使いやすいライブラリは見つかりませんでした

ここにリストされているように、設定ファイルを複数の特別なフォルダー(すべてのユーザーとユーザーごと)に保存できます。Environment.SpecialFolder列挙と複数のファイル(デフォルトは読み取り専用、役割ごと、ユーザーごとなど)

複数の設定を使用することを選択した場合、それらの設定をマージできます。たとえば、デフォルト+ BasicUser + AdminUserの設定をマージします。独自のルールを使用できます。最後のルールは値をオーバーライドします。


4

「これは、構成設定を保存するためにカスタムXMLファイルを使用する必要があるということですか?」いいえ、必ずしもそうとは限りません。そのような操作にはSharpConfigを使用します。

たとえば、構成ファイルがそのような場合

[General]
# a comment
SomeString = Hello World!
SomeInteger = 10 # an inline comment

このような値を取得できます

var config = Configuration.LoadFromFile("sample.cfg");
var section = config["General"];

string someString = section["SomeString"].StringValue;
int someInteger = section["SomeInteger"].IntValue;

.NET 2.0以降と互換性があります。その場で構成ファイルを作成し、後で保存することができます。

ソース:http : //sharpconfig.net/
GitHub:https : //github.com/cemdervis/SharpConfig


3

私の知る限り、.NETは組み込みのアプリケーション設定機能を使用して設定の永続化をサポートしています。

Windowsフォームのアプリケーション設定機能を使用すると、クライアントコンピューターでカスタムアプリケーションとユーザー設定を簡単に作成、保存、維持できます。Windowsフォームアプリケーションの設定では、データベース接続文字列などのアプリケーションデータだけでなく、ユーザーアプリケーションの設定などのユーザー固有のデータも保存できます。Visual Studioまたはカスタムマネージコードを使用して、新しい設定の作成、ディスクからの読み取りと書き込み、フォームのプロパティへのバインド、および読み込みと保存の前に設定データの検証を行うことができます。- http://msdn.microsoft.com/en-us/library/k4s6c3a0.aspx


2
正しくありません。上記のakuの回答を参照してください。設定とApplicationSettingsBase使用して、その可能性
Gishu

2

従来のweb.configまたはapp.configファイルに保持されているこれらの設定を削除したい場合があります。設定エントリと分離されたデータ設計の展開をより細かく制御したい。または、実行時に新しいエントリを追加できるようにする必要があります。

私は2つの適切なオプションを想像できます。

  • 強く型付けされたバージョンと
  • オブジェクト指向バージョン。

厳密に型指定されたバージョンの利点は、厳密に型指定された設定の名前と値です。名前やデータ型が混在するリスクはありません。欠点は、コード化する必要がある設定が多く、実行時に追加できないことです。

オブジェクト指向バージョンの利点は、実行時に新しい設定を追加できることです。しかし、厳密に型指定された名前と値はありません。文字列識別子には注意が必要です。値を取得するときに、以前に保存されたデータ型を知っている必要があります。

両方の完全に機能する実装のコードはここにあります。


2

はい、設定を保存することは可能です -しかし、それはあなたがそれを行うことを選択した方法にかなり依存します。あなたが持っているオプションを理解できるように、技術的な違いを説明しましょう。

あなたが使用したいかどうかをまず、あなたは、区別する必要がapplicationSettingsのAppSettingsをあなたに*.exe.config(別名App.configがある- Visual Studioで)ファイルの基本的な違いは、 ここで説明されています

どちらも、変更を保存するさまざまな方法を提供します。

  • AppSettingsはあなたが読んで(を経由して設定ファイルに直接書き込むことができるようにconfig.Save(ConfigurationSaveMode.Modified);設定は次のように定義され、config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);)。

  • applicationSettingsは読み取ることができますが、あなたは(経由で変更を書き込む場合Properties.Settings.Default.Save();)には特別な場所(例えばに保存され、ユーザごとのベースで書き込まれますC:\Documents and Settings\USERID\Local Settings\Application Data\FIRMNAME\WindowsFormsTestApplicati_Url_tdq2oylz33rzq00sxhvxucu5edw2oghw\1.0.0.0)。以下のようハンスアンパッサンは、言及した彼の答えでは通常、ユーザーがプログラムファイルへのアクセス権が制限されていて、プロンプトUACを起動せずに、それに書き込むことはできませんので、これはです。欠点は、将来設定キーを追加する場合、それらをすべてのユーザープロファイルと同期する必要があることです。

注:質問で述べたように、3番目のオプションがあります。構成ファイルをXMLドキュメントとして扱う場合、System.Xml.Linq.XDocumentクラスを使用してファイルをロード、変更、保存できます。カスタムXMLファイルを使用する必要はありません。既存の構成ファイルを読み取ることができます。要素のクエリには、Linqクエリを使用することもできます。私はここで例を挙げましGetApplicationSettingた、答えでそこの関数をチェックしてください。

値を保護するために暗号化が必要な場合は、この回答を確認してください。


この素晴らしい答えをありがとう。
NoChance

2
@NoChance-どういたしまして、私があなたを助けることができてうれしいです!
マット

いいね!最後にすべてのアウト😂😂😂考え出し
Momoro

1
@Momoro-聞いてよかった!;-)
マット

1
public static class SettingsExtensions
{
    public static bool TryGetValue<T>(this Settings settings, string key, out T value)
    {
        if (settings.Properties[key] != null)
        {
            value = (T) settings[key];
            return true;
        }

        value = default(T);
        return false;
    }

    public static bool ContainsKey(this Settings settings, string key)
    {
        return settings.Properties[key] != null;
    }

    public static void SetValue<T>(this Settings settings, string key, T value)
    {
        if (settings.Properties[key] == null)
        {
            var p = new SettingsProperty(key)
            {
                PropertyType = typeof(T),
                Provider = settings.Providers["LocalFileSettingsProvider"],
                SerializeAs = SettingsSerializeAs.Xml
            };
            p.Attributes.Add(typeof(UserScopedSettingAttribute), new UserScopedSettingAttribute());
            var v = new SettingsPropertyValue(p);
            settings.Properties.Add(p);
            settings.Reload();
        }
        settings[key] = value;
        settings.Save();
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.