c# विंडोज़ फॉर्म एप्लिकेशन में एप्लिकेशन सेटिंग्स को सहेजने का सर्वोत्तम अभ्यास




xml winforms (11)

मैं जो हासिल करना चाहता हूं वह बहुत आसान है: मेरे पास एक विंडोज फॉर्म (.NET 3.5) एप्लिकेशन है जो जानकारी पढ़ने के लिए पथ का उपयोग करता है। मेरे द्वारा प्रदान किए गए विकल्प फ़ॉर्म का उपयोग करके, इस पथ को उपयोगकर्ता द्वारा संशोधित किया जा सकता है।

अब, मैं बाद में उपयोग के लिए पथ मान को फ़ाइल में सहेजना चाहता हूं। यह इस फ़ाइल में सहेजी गई कई सेटिंग्स में से एक होगा। यह फ़ाइल सीधे एप्लिकेशन फ़ोल्डर में बैठेगी।

मैं समझता हूं कि तीन विकल्प उपलब्ध हैं:

  • कॉन्फ़िगरेशन सेटिंग्स फ़ाइल (appname.exe.config)
  • रजिस्ट्री
  • कस्टम एक्सएमएल फ़ाइल

मैंने पढ़ा है कि .NET कॉन्फ़िगरेशन फ़ाइल वापस मूल्यों को सहेजने के लिए पूर्ववत नहीं है। रजिस्ट्री के लिए, मैं जितना संभव हो उससे दूर जाना चाहता हूं।

क्या इसका मतलब यह है कि कॉन्फ़िगरेशन सेटिंग्स को सहेजने के लिए मुझे कस्टम 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/ गीथूब: https://github.com/cemdervis/SharpConfig

मुझे उम्मीद है यह मदद करेगा।


जहां तक ​​मैं कह सकता हूं, .NET अंतर्निहित एप्लिकेशन सेटिंग्स सुविधा का उपयोग कर स्थायी सेटिंग्स का समर्थन करता है:

विंडोज फॉर्म की एप्लिकेशन सेटिंग्स सुविधा क्लाइंट कंप्यूटर पर कस्टम एप्लिकेशन और उपयोगकर्ता प्राथमिकताओं को बनाना, स्टोर करना और बनाए रखना आसान बनाता है। विंडोज़ फॉर्म एप्लिकेशन सेटिंग्स के साथ, आप न केवल डाटाबेस कनेक्शन स्ट्रिंग जैसे एप्लिकेशन डेटा स्टोर कर सकते हैं, बल्कि उपयोगकर्ता-विशिष्ट डेटा, जैसे उपयोगकर्ता एप्लिकेशन वरीयताओं को भी स्टोर कर सकते हैं। विजुअल स्टूडियो या कस्टम प्रबंधित कोड का उपयोग करके, आप नई सेटिंग्स बना सकते हैं, उन्हें पढ़ सकते हैं और उन्हें डिस्क पर लिख सकते हैं, उन्हें अपने फॉर्मों पर गुणों से जोड़ सकते हैं, और लोड करने और सहेजने से पहले सेटिंग्स डेटा को सत्यापित कर सकते हैं। - http://msdn.microsoft.com/en-us/library/k4s6c3a0.aspx


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

मैं इसके लिए बनाई गई लाइब्रेरी साझा करना चाहता था। यह एक छोटी पुस्तकालय है, लेकिन एक बड़ी सुधार (आईएमएचओ) .settings फ़ाइलों पर।

पुस्तकालय को जॉट (गिटहब) कहा जाता है, यहां एक पुराना कोड प्रोजेक्ट आलेख है जिसे मैंने इसके बारे में लिखा था।

यहां बताया गया है कि आप विंडो के आकार और स्थान का ट्रैक रखने के लिए इसका उपयोग कैसे करेंगे:

public MainWindow()
{
    InitializeComponent();

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

.settings फ़ाइलों की तुलना में लाभ: काफी कम कोड है, और यह बहुत कम त्रुटि-प्रवण है क्योंकि आपको केवल एक बार प्रत्येक संपत्ति का उल्लेख करने की आवश्यकता है।

एक सेटिंग फाइलों के साथ आपको प्रत्येक संपत्ति को पांच बार उल्लेख करने की आवश्यकता होती है: एक बार जब आप स्पष्ट रूप से संपत्ति बनाते हैं और उस कोड में अतिरिक्त चार बार होते हैं जो मूल्यों को प्रतिलिपि बनाता है।

भंडारण, क्रमबद्धता, आदि पूरी तरह से विन्यास योग्य हैं। नियंत्रण में उलटा उपयोग करते समय, आप इसे हुक कर सकते हैं ताकि यह स्वचालित रूप से सभी ऑब्जेक्ट्स को ट्रैक करने पर लागू हो जाए ताकि आपको संपत्ति को लगातार बनाने के लिए जो कुछ करना है, वह उस पर एक [ट्रैक करने योग्य] विशेषता है।

मैं यह सब लिख रहा हूं, क्योंकि मुझे लगता है कि पुस्तकालय शीर्ष पायदान है, और मैं इसे लोकप्रिय बनाना चाहता हूं :)


रजिस्ट्री एक नो-गो है। आप सुनिश्चित नहीं हैं कि आपके एप्लिकेशन का उपयोग करने वाले उपयोगकर्ता के पास रजिस्ट्री को लिखने के पर्याप्त अधिकार हैं या नहीं।

आप एप्लिकेशन-स्तरीय सेटिंग्स को सहेजने के लिए app.config फ़ाइल का उपयोग कर सकते हैं (जो आपके उपयोगकर्ता का उपयोग करने वाले प्रत्येक उपयोगकर्ता के लिए समान हैं)।

मैं उपयोगकर्ता-विशिष्ट सेटिंग्स को एक XML फ़ाइल में संग्रहीत करता हूं, जिसे पृथक संग्रहण में या SpecialFolder.ApplicationData में सहेजा जाएगा। SpecialFolder.ApplicationData निर्देशिका।

उसके आगे, .NET 2.0 के रूप में, मानों को वापस app.config फ़ाइल में संग्रहीत करना संभव है।



कभी-कभी आप परंपरागत web.config या app.config फ़ाइल में रखी गई सेटिंग्स से छुटकारा पाना चाहते हैं। आप अपनी सेटिंग्स प्रविष्टियों और अलग डेटा डिज़ाइन की तैनाती पर अधिक बढ़िया नियंत्रण चाहते हैं। या आवश्यकता रनटाइम पर नई प्रविष्टियों को जोड़ने में सक्षम है।

मैं दो अच्छे विकल्पों की कल्पना कर सकता हूं:

  • दृढ़ता से टाइप संस्करण और
  • वस्तु उन्मुख संस्करण।

दृढ़ता से टाइप किए गए संस्करण का लाभ दृढ़ता से टाइप की गई सेटिंग्स के नाम और मान हैं। नाम या डेटा प्रकारों को अंतःस्थापित करने का कोई जोखिम नहीं है। नुकसान यह है कि अधिक सेटिंग्स को कोड किया जाना है, रनटाइम पर जोड़ा नहीं जा सकता है।

ऑब्जेक्ट उन्मुख संस्करण के साथ लाभ यह है कि रनटाइम पर नई सेटिंग्स को जोड़ा जा सकता है। लेकिन आपने दृढ़ता से टाइप किए गए नाम और मूल्य नहीं उठाए हैं। स्ट्रिंग पहचानकर्ताओं के साथ सावधान रहना चाहिए। मूल्य प्राप्त करते समय पहले सहेजे गए डेटा प्रकार को अवश्य जानना चाहिए।

आप HERE पूरी तरह कार्यात्मक कार्यान्वयन दोनों का कोड पा सकते हैं।


रजिस्ट्री / कॉन्फ़िगरेशन सेटिंग्स / एक्सएमएल तर्क अभी भी बहुत सक्रिय लगता है। मैंने उन सभी का उपयोग किया है, क्योंकि तकनीक की प्रगति हुई है, लेकिन मेरा पसंदीदा थ्रीड सिस्टम पर पृथक भंडारण के साथ संयुक्त है।

निम्नलिखित नमूना अलग-अलग भंडारण में एक फ़ाइल के गुणों वाले गुणों के संग्रहण की अनुमति देता है। जैसे कि:

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) { }
        }
    }
}

ApplicationSettings क्लास app.config फ़ाइल में सहेजने की सेटिंग्स का समर्थन नहीं करता है। यह डिज़ाइन द्वारा बहुत अधिक है, एक उचित ढंग से सुरक्षित उपयोगकर्ता खाते (लगता है कि Vista UAC) के साथ चलने वाले ऐप्स प्रोग्राम के इंस्टॉलेशन फ़ोल्डर में लेखन पहुंच नहीं रखते हैं।

आप ConfigurationManager क्लास के साथ सिस्टम से लड़ सकते हैं। लेकिन मामूली कामकाज सेटिंग डिजाइनर में जाना है और उपयोगकर्ता के लिए सेटिंग का दायरा बदलना है। यदि यह कठिनाइयों का कारण बनता है (कहें, सेटिंग प्रत्येक उपयोगकर्ता के लिए प्रासंगिक है), तो आपको अपनी विकल्प सुविधा को एक अलग प्रोग्राम में रखना चाहिए ताकि आप विशेषाधिकार उन्नयन संकेत मांग सकें। या एक सेटिंग का उपयोग कर forego।


यदि आप अपने निष्पादन योग्य के समान निर्देशिका में फ़ाइल को सहेजने की योजना बना रहे हैं, तो यहां एक अच्छा समाधान है जो 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;
        }
    }
}

कॉन्फ़िगरेशन डेटा ऑब्जेक्ट का उपयोग करने का एक आसान तरीका है, इसे स्थानीय फ़ोल्डर में एप्लिकेशन के नाम से एक्सएमएल फ़ाइल के रूप में सहेजें और स्टार्टअप पर इसे वापस पढ़ें।

एक फॉर्म की स्थिति और आकार को स्टोर करने के लिए यहां एक उदाहरण दिया गया है।

कॉन्फ़िगरेशन डेटाबोजेक्ट दृढ़ता से टाइप किया गया है और उपयोग करने में आसान है:

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




application-settings