Development Tip

Windows Forms 응용 프로그램에서 응용 프로그램 설정을 저장하는 방법은 무엇입니까?

yourdevel 2020. 10. 3. 12:05
반응형

Windows Forms 응용 프로그램에서 응용 프로그램 설정을 저장하는 방법은 무엇입니까?


내가 원하는 것은 매우 간단합니다. 정보를 읽는 데 경로를 사용하는 Windows Forms (.NET 3.5) 응용 프로그램이 있습니다. 이 경로는 내가 제공하는 옵션 양식을 사용하여 사용자가 수정할 수 있습니다.

이제 나중에 사용할 수 있도록 경로 값을 파일에 저장하고 싶습니다. 이것은이 파일에 저장된 많은 설정 중 하나입니다. 이 파일은 응용 프로그램 폴더에 직접 저장됩니다.

세 가지 옵션을 사용할 수 있음을 이해합니다.

  • ConfigurationSettings 파일 (appname.exe.config)
  • 기재
  • 사용자 정의 XML 파일

.NET 구성 파일이 값을 다시 저장하기 위해 예상되지 않는다는 것을 읽었습니다. 레지스트리에 관해서는 가능한 한 멀리하고 싶습니다.

이것은 구성 설정을 저장하기 위해 사용자 지정 XML 파일을 사용해야 함을 의미합니까? 그렇다면 해당 코드 예제 (C #)를보고 싶습니다.

이 주제에 대한 다른 토론을 보았지만 아직 명확하지 않습니다.


Visual Studio로 작업하는 경우 지속 가능한 설정을 얻는 것이 매우 쉽습니다. 솔루션 탐색기에서 프로젝트를 마우스 오른쪽 단추로 클릭하고 속성을 선택합니다. 설정 탭을 선택하고 설정이 없으면 하이퍼 링크를 클릭합니다. 설정 탭을 사용하여 응용 프로그램 설정을 만듭니다. Visual Studio에서 파일을 생성 Settings.settings하고 Settings.Designer.settings그 싱글 톤 클래스를 포함 Settings로부터 상속 ApplicationSettingsBase을 . 코드에서이 클래스에 액세스하여 애플리케이션 설정을 읽고 쓸 수 있습니다.

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

이 기술은 콘솔, Windows Forms 및 기타 프로젝트 유형 모두에 적용됩니다.

설정의 범위 속성 을 설정해야합니다 . 응용 프로그램 범위를 선택하면 Settings.Default. <속성> 읽기 전용이됩니다.


실행 파일과 동일한 디렉토리 내의 파일에 저장할 계획이라면 다음은 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 디렉터리 저장되는 XML 파일에 저장 합니다.

그 다음에 .NET 2.0에서와 같이 값을 app.config파일에 다시 저장할 수 있습니다.


ApplicationSettings클래스는 app.config 파일에 설정 저장을 지원하지 않습니다. 이는 설계 상 적절하게 보안 된 사용자 계정 (예 : Vista UAC)으로 실행되는 앱에는 프로그램의 설치 폴더에 대한 쓰기 권한이 없습니다.

ConfigurationManager클래스 와 함께 시스템과 싸울 수 있습니다 . 그러나 간단한 해결 방법은 설정 디자이너로 이동하여 설정 범위를 사용자로 변경하는 것입니다. 이로 인해 어려움이 발생하는 경우 (예 : 설정이 모든 사용자와 관련이 있음) 권한 상승 프롬프트를 요청할 수 있도록 별도의 프로그램에 옵션 기능을 배치해야합니다. 또는 설정을 사용하지 마십시오.


이를 위해 구축 한 라이브러리를 공유하고 싶었습니다. 작은 라이브러리이지만 .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언급해야합니다. 속성 을 명시 적으로 만들 때 한 번, 값을 앞뒤로 복사하는 코드에서 추가로 4 번 언급해야 합니다.

스토리지, 직렬화 등은 완전히 구성 할 수 있습니다. 대상 개체가 IOC 컨테이너에 의해 생성 될 때 [연결] []하여 확인하는 모든 개체에 추적을 자동으로 적용하여 속성을 영구적으로 만들기 위해해야 ​​할 일은 [추적 가능] 속성을 슬랩하는 것뿐입니다. 그 위에.

고도로 구성 가능하며 다음을 구성 할 수 있습니다.-데이터가 전역 적으로 유지되고 적용될 때 또는 추적 된 각 개체에 대해-직렬화 방법-저장 위치 (예 : 파일, 데이터베이스, 온라인, 격리 된 저장소, 레지스트리)-적용 / 지속을 취소 할 수있는 규칙 속성 데이터

저를 믿으십시오. 도서관은 최고 수준입니다!


registry / configurationSettings / XML 인수는 여전히 매우 활성화 된 것 같습니다. 기술이 발전함에 따라 모두 사용했지만 제가 가장 좋아하는 것은 Isolated Storage 와 결합 된 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) { }
        }
    }
}

간단한 방법은 구성 데이터 개체를 사용하고 로컬 폴더에 응용 프로그램 이름과 함께 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();
    }

And the produced XML file is also readable:

<?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>

I don't like the proposed solution of using web.config or app.config. Try reading your own XML. Have a look at XML Settings Files – No more web.config.


Other options, instead of using a custom XML file, we can use a more user friendly file format: JSON or YAML file.

  • If you use .NET 4.0 dynamic, this library is really easy to use (serialize, deserialize, nested objects support and ordering output as you wish + merging multiple settings to one) JsonConfig (usage is equivalent to ApplicationSettingsBase)
  • For .NET YAML configuration library... I haven't found one that is as easy to use as JsonConfig

You can store your settings file in multiple special folders (for all users and per user) as listed here Environment.SpecialFolder Enumeration and multiple files (default read only, per role, per user, etc.)

If you choose to use multiple settings, you can merge those settings: For example, merging settings for default + BasicUser + AdminUser. You can use your own rules: the last one overrides the value, etc.


"Does this mean that I should use a custom XML file to save configuration settings?" No, not necessarily. We use SharpConfig for such operations.

For instance, if config file is like that

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

We can retrieve values like this

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

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

It is compatible with .Net 2.0 and higher. We can create config files on the fly and we can save it later. Source: http://sharpconfig.net/ Github: https://github.com/cemdervis/SharpConfig

I hope it helps.


As far as I can tell, .NET does support persisting settings using the built-in application settings facility:

The Application Settings feature of Windows Forms makes it easy to create, store, and maintain custom application and user preferences on the client computer. With Windows Forms application settings, you can store not only application data such as database connection strings, but also user-specific data, such as user application preferences. Using Visual Studio or custom managed code, you can create new settings, read them from and write them to disk, bind them to properties on your forms, and validate settings data prior to loading and saving. - http://msdn.microsoft.com/en-us/library/k4s6c3a0.aspx


Sometimes you want to get rid of those settings kept in the traditional web.config or app.config file. You want more fine grained control over the deployment of your settings entries and separated data design. Or the requirement is to enable adding new entries at runtime.

I can imagine two good options:

  • The strongly typed version and
  • The object oriented version.

The advantage of the strongly typed version are the strongly typed settings names and values. There is no risk of intermixing names or data types. The disadvantage is that more settings have to be coded, cannot be added at runtime.

With the object oriented version the advantage is that new settings can be added at runtime. But you do not have strongly typed names and values. Must be careful with string identifiers. Must know data type saved earlier when getting a value.

You can find the code of both fully functional implementations HERE.


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();
    }
}

참고URL : https://stackoverflow.com/questions/453161/how-to-save-application-settings-in-a-windows-forms-application

반응형