Windows フォーム アプリケーションにアプリケーション設定を保存するにはどうすればよいですか?
-
19-08-2019 - |
質問
私が達成したいことは非常にシンプルです:情報の読み取りにパスを使用する Windows フォーム (.NET 3.5) アプリケーションがあります。このパスは、私が提供するオプション フォームを使用してユーザーが変更できます。
ここで、後で使用できるようにパス値をファイルに保存したいと思います。これは、このファイルに保存されている多くの設定のうちの 1 つです。このファイルはアプリケーション フォルダーに直接配置されます。
3 つのオプションが利用可能であることを理解しています。
- 構成設定ファイル (appname.exe.config)
- レジストリ
- カスタムXMLファイル
.NET 構成ファイルには値を保存することは想定されていないと読みました。レジストリに関しては、できるだけ距離を置きたいと思っています。
これは、構成設定を保存するにはカスタム XML ファイルを使用する必要があるという意味ですか?もしそうなら、そのコード例 (C#) を見てみたいと思います。
このテーマに関する他の議論を見ましたが、まだよくわかりません。
解決
Visual Studioを使用している場合、永続的な設定を取得するのは非常に簡単です。ソリューションエクスプローラーでプロジェクトを右クリックし、[プロパティ]を選択します。 [設定]タブを選択し、設定が存在しない場合はハイパーリンクをクリックします。 [設定]タブを使用して、アプリケーション設定を作成します。 Visual Studioは、Settings.Designer.settings
およびSettings
を作成します"rel =" noreferrer "> ApplicationSettingsBase 。コードからこのクラスにアクセスして、アプリケーション設定の読み取り/書き込みを行うことができます。
Properties.Settings.Default["SomeProperty"] = "Some Value";
Properties.Settings.Default.Save(); // Saves settings in application configuration file
この手法は、コンソール、Windowsフォーム、およびその他のプロジェクトタイプの両方に適用できます。
設定の scope プロパティを設定する必要があることに注意してください。アプリケーションスコープを選択すると、Settings.Default。<!> lt;あなたの財産<!> gt;読み取り専用になります。
他のヒント
実行可能ファイルと同じディレクトリ内のファイルに保存することを計画している場合、 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;
}
}
}
レジストリは不許可です。アプリケーションを使用するユーザーがレジストリに書き込むための十分な権限を持っているかどうかはわかりません。
app.config
ファイルを使用して、アプリケーションレベルの設定を保存できます(アプリケーションを使用する各ユーザーで同じです)。
分離ストレージまたは SpecialFolder.ApplicationData ディレクトリ。
その次に、.NET 2.0から、値を<=>ファイルに保存することができます。
ApplicationSettings
クラスは、app.configファイルへの設定の保存をサポートしていません。これは、設計上非常に重要です。適切に保護されたユーザーアカウント(Vista UACなど)で実行されるアプリには、プログラムのインストールフォルダーへの書き込みアクセス権がありません。
ConfigurationManager
クラスを使用してシステムと戦うことができます。しかし、簡単な回避策は、設定デザイナーに移動し、設定の範囲をユーザーに変更することです。それが困難な場合(たとえば、設定がすべてのユーザーに関連する場合)、特権の昇格のプロンプトを要求できるように、オプション機能を別のプログラムに配置する必要があります。または、設定を使用して先送りします。
registry/configurationSettings/XML 引数はまだ非常にアクティブであるようです。テクノロジーの進歩に伴い、私はそれらをすべて使用してきましたが、私のお気に入りは、 スリーズのシステム と組み合わせ 隔離されたストレージ.
次のサンプルでは、properties という名前のオブジェクトを分離ストレージ内のファイルに保存できます。のような:
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) { }
}
}
}
このために作成したライブラリを共有したかった。これは小さなライブラリですが、.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回はプロパティを明示的に作成し、もう4回は値を前後にコピーするコードで追加します。
ストレージ、シリアル化などは完全に構成可能です。ターゲットオブジェクトがIOCコンテナによって作成されると、[フックアップ] []して、解決するすべてのオブジェクトに追跡を自動的に適用し、プロパティを永続化するために必要なことは[Trackable]属性をスラップするだけです。その上。
高度な設定が可能です。次の設定が可能です。 -データが永続的に適用され、グローバルに、または追跡対象の各オブジェクトに適用される場合 -シリアル化方法 -保存場所(ファイル、データベース、オンライン、分離ストレージ、レジストリなど) -プロパティのデータの適用/保持をキャンセルできるルール
信頼してください、ライブラリは最高です!
簡単な方法は、構成データオブジェクトを使用し、ローカルフォルダにアプリケーションの名前を付けて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();
}
}
}
インスタンスを作成し、フォームのロードイベントとクローズイベントで使用できるようになりました。
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>
web.config
またはapp.config
を使用する提案された解決策が気に入らない。独自のXMLを読んでみてください。 XML設定ファイル<!>#8211;これ以上web.config はありません。
他のオプションでは、カスタムXMLファイルを使用する代わりに、JSONまたはYAMLファイルのユーザーフレンドリなファイル形式を使用できます。
- .NET 4.0ダイナミックを使用する場合、このライブラリは非常に使いやすい (出力のシリアル化、逆シリアル化、ネストされたオブジェクトのサポートと順序付け 必要に応じて、複数の設定を1つにマージします) JsonConfig (使用法はApplicationSettingsBaseと同等です)
- .NET YAML構成ライブラリの場合...次のようなものが見つかりません JsonConfigとして使いやすい
Environment.SpecialFolder列挙および複数のファイル(デフォルトは読み取り専用、ロールごと、ユーザーごとなど)
- 特別なフォルダーのパスを取得するサンプル: C#のパスを取得 %AppData%
複数の設定を使用することを選択した場合、それらの設定をマージできます。たとえば、デフォルト+ BasicUser + AdminUserの設定をマージします。独自のルールを使用できます。最後のルールが値などをオーバーライドします。
<!> quot;これは、カスタムXMLファイルを使用して構成設定を保存する必要があるということですか?<!> quot;いいえ、必ずしもそうではありません。そのような操作には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
お役に立てば幸いです。
私が知る限り、.NETは組み込みのアプリケーション設定機能を使用した設定の永続化をサポートしています。
Windowsフォームのアプリケーション設定機能を使用すると、クライアントコンピューターでカスタムアプリケーションとユーザー設定を簡単に作成、保存、および管理できます。 Windowsフォームアプリケーションの設定を使用すると、データベース接続文字列などのアプリケーションデータだけでなく、ユーザーアプリケーションの設定などのユーザー固有のデータも保存できます。 Visual Studioまたはカスタムマネージコードを使用して、新しい設定の作成、ディスクからの読み取りとディスクへの書き込み、フォームのプロパティへのバインド、および読み込みと保存の前に設定データを検証できます。 - http://msdn.microsoft.com/en-us/library/k4s6c3a0 .aspx
場合によっては、従来のweb.configまたはapp.configファイルに保存されているこれらの設定を削除したいことがあります。設定エントリと分離されたデータ設計の展開をより詳細に制御したい場合。または、実行時に新しいエントリを追加できるようにする必要があります。
2つの優れたオプションを想像できます。
- 強く型付けされたバージョン
- オブジェクト指向バージョン。
強く型付けされたバージョンの利点は、強く型付けされた設定の名前と値です。名前やデータ型が混在するリスクはありません。欠点は、より多くの設定をコーディングする必要があり、実行時に追加できないことです。
オブジェクト指向バージョンの利点は、実行時に新しい設定を追加できることです。ただし、厳密に型指定された名前と値はありません。文字列識別子には注意する必要があります。値を取得するときに、以前に保存されたデータ型を知っている必要があります。
完全に機能する両方の実装のコードを見つけることができますこちら。
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();
}
}