एक WPF आवेदन में उपयोगकर्ता सेटिंग्स को बचाने के लिए दृष्टिकोण #?


84

WPF विंडो (डेस्कटॉप) एप्लिकेशन में उपयोगकर्ता सेटिंग्स को बनाए रखने के लिए आप क्या दृष्टिकोण सुझाते हैं? ध्यान दें कि विचार यह है कि उपयोगकर्ता रन समय में अपनी सेटिंग्स को बदल सकता है, और फिर एप्लिकेशन को बंद कर सकता है, फिर आवेदन शुरू करने के बाद जब एप्लिकेशन वर्तमान सेटिंग्स का उपयोग करेगा। प्रभावी रूप से तब यह दिखाई देगा जैसे कि एप्लिकेशन सेटिंग नहीं बदलती हैं।

Q1 - डेटाबेस या अन्य दृष्टिकोण? मेरे पास एक sqlite डेटाबेस है जिसे मैं वैसे भी उपयोग कर रहा हूं इसलिए डेटाबेस में एक तालिका का उपयोग करना किसी भी दृष्टिकोण के रूप में अच्छा होगा?

Q2 - यदि डेटाबेस: क्या डेटाबेस तालिका डिजाइन? विभिन्न डेटा प्रकार के लिए कॉलम के साथ एक मेज से एक हो सकता है (उदाहरण के लिए string, long, DateTimeआदि) या बस जिस पर आप serialize और de-serialize मूल्यों के लिए है मूल्य के लिए एक स्ट्रिंग के साथ एक मेज? मुझे लगता है कि पहला आसान होगा, और अगर कई सेटिंग्स नहीं हैं तो ओवरहेड ज्यादा नहीं है?

Q3 - क्या इसके लिए एप्लिकेशन सेटिंग्स का उपयोग किया जा सकता है? यदि ऐसा है तो यहाँ दृढ़ता को सक्षम करने के लिए किसी विशेष कार्य की आवश्यकता है? इस मामले में एप्लिकेशन सेटिंग्स डिजाइनर में "डिफ़ॉल्ट" मान के उपयोग के बारे में भी क्या होगा? क्या डिफॉल्ट एप्लिकेशन को चलाने के बीच बचाई गई किसी भी सेटिंग को ओवरराइड करेगा? (या आपको डिफ़ॉल्ट मान का उपयोग करने की आवश्यकता नहीं होगी)


@ सभी नए उपयोगकर्ता इसे पसंद करते हैं यदि आप अपने प्रश्नों को एक में संयोजित करने के बजाय अलग-अलग प्रश्न पोस्ट कर सकते हैं। इस तरह, यह लोगों को आपके प्रश्न का उत्तर देने में मदद करता है और दूसरों को आपके कम से कम एक प्रश्न का शिकार होने में मदद करता है। धन्यवाद!
हिले

जवाबों:


80

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

यहां कुछ लिंक दिए गए हैं जो बताते हैं कि इसे कैसे हासिल किया जाए और उन्हें WPF में इस्तेमाल किया जाए -

WPF में उपयोगकर्ता सेटिंग्स

त्वरित WPF टिप: WPF अनुप्रयोग संसाधनों और सेटिंग्स से कैसे जुड़ें?

WPF के लिए एक विन्यास योग्य विंडो


22

अपडेट : आजकल मैं JSON का उपयोग करता हूं।

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

  1. अपनी सभी सेटिंग्स के साथ कहीं न कहीं एक क्लास करें। मैंने इसका नाम रखाMySettings
  2. दृढ़ता के लिए सहेजें और पढ़ें को लागू करें
  3. आप अनुप्रयोग-कोड में उनका उपयोग करें

लाभ:

  • बहुत ही सरल दृष्टिकोण।
  • सेटिंग्स के लिए एक वर्ग। भार। सहेजें।
  • आपकी सभी सेटिंग्स सुरक्षित हैं।
  • आप अपनी आवश्यकताओं के तर्क को सरल या विस्तारित कर सकते हैं (संस्करण, प्रति उपयोगकर्ता कई प्रोफाइल, आदि)
  • यह किसी भी मामले में बहुत अच्छा काम करता है (डेटाबेस, WinForms, WPF, Service, etc ...)
  • आप एक्सएमएल फाइलों को स्टोर करने के लिए परिभाषित कर सकते हैं।
  • आप उन्हें पा सकते हैं और कोड या मैनुअल द्वारा उन्हें हेरफेर कर सकते हैं
  • यह किसी भी तैनाती पद्धति के लिए काम करता है जिसकी मैं कल्पना कर सकता हूं।

नुकसान: - आपको यह सोचना होगा कि अपनी सेटिंग्स फ़ाइलों को कहाँ संग्रहीत करें। (लेकिन आप केवल अपने इंस्टॉलेशन फ़ोल्डर का उपयोग कर सकते हैं)

यहाँ एक सरल उदाहरण है (परीक्षण नहीं किया गया है) -

public class MySettings
{
    public string Setting1 { get; set; }
    public List<string> Setting2 { get; set; }

    public void Save(string filename)
    {
        using (StreamWriter sw = new StreamWriter(filename))
        {
            XmlSerializer xmls = new XmlSerializer(typeof(MySettings));
            xmls.Serialize(sw, this);
        }
    }
    public MySettings Read(string filename)
    {
        using (StreamReader sw = new StreamReader(filename))
        {
            XmlSerializer xmls = new XmlSerializer(typeof(MySettings));
            return xmls.Deserialize(sw) as MySettings;
        }
    }
}

और यहाँ इसका उपयोग कैसे करना है। डिफ़ॉल्ट मान लोड करना संभव है या उपयोगकर्ता की सेटिंग मौजूद होने पर केवल जाँच करके उन्हें उपयोगकर्ता की सेटिंग से ओवरराइड कर सकते हैं:

public class MyApplicationLogic
{
    public const string UserSettingsFilename = "settings.xml";
    public string _DefaultSettingspath = 
        Assembly.GetEntryAssembly().Location + 
        "\\Settings\\" + UserSettingsFilename;

    public string _UserSettingsPath = 
        Assembly.GetEntryAssembly().Location + 
        "\\Settings\\UserSettings\\" + 
        UserSettingsFilename;

    public MyApplicationLogic()
    {
        // if default settings exist
        if (File.Exists(_UserSettingsPath))
            this.Settings = Settings.Read(_UserSettingsPath);
        else
            this.Settings = Settings.Read(_DefaultSettingspath);
    }
    public MySettings Settings { get; private set; }

    public void SaveUserSettings()
    {
        Settings.Save(_UserSettingsPath);
    }
}

हो सकता है कि कोई इस दृष्टिकोण से प्रेरित हो। यह है कि मैं इसे अभी कई वर्षों से कर रहा हूं और मैं इससे काफी खुश हूं।


1
नुकसान के लिए, यह होगा कि आपके पास सेटिंग्स डिजाइनर अब नहीं हैं, इसलिए यह थोड़ा कम उपयोगकर्ता के अनुकूल है जब दोनों काम करेंगे।
1919 में Phil1970

3
पूरी तरह से "बहुत अजीब व्यवहार जहां वे संग्रहीत हैं" पर सहमत हैं, मैं इस वजह से आपके दृष्टिकोण का सटीक उपयोग कर रहा हूं। +1।
हन्नीश

यदि आपके पास कोई नया प्रश्न है, तो कृपया प्रश्न पूछें बटन पर क्लिक करके पूछें
Mat

12

आप अपनी सेटिंग्स की जानकारी StringsXML के रूप में स्टोर कर सकते हैं Settings.Default। अपने कॉन्फ़िगरेशन डेटा को संग्रहीत करने के लिए कुछ कक्षाएं बनाएं और सुनिश्चित करें कि वे हैं [Serializable]। फिर, निम्न सहायकों के साथ, आप इन वस्तुओं के उदाहरणों को क्रमबद्ध कर सकते हैं - या List<T>(या सरणियाँ T[], आदि) - से StringSettings.Defaultअपने WPF एप्लिकेशन में अपने संबंधित स्लॉट में इन विभिन्न तारों में से प्रत्येक को स्टोर करें Settings

अगली बार जब ऐप शुरू होता है, तो वस्तुओं को पुनर्प्राप्त करने के लिए, Settingsब्याज की स्ट्रिंग और Deserializeअपेक्षित प्रकार T(जो इस समय को एक प्रकार के तर्क के रूप में स्पष्ट रूप से निर्दिष्ट किया जाना चाहिए) को पढ़ें Deserialize<T>

public static String Serialize<T>(T t)
{
    using (StringWriter sw = new StringWriter())
    using (XmlWriter xw = XmlWriter.Create(sw))
    {
        new XmlSerializer(typeof(T)).Serialize(xw, t);
        return sw.GetStringBuilder().ToString();
    }
}

public static T Deserialize<T>(String s_xml)
{
    using (XmlReader xw = XmlReader.Create(new StringReader(s_xml)))
        return (T)new XmlSerializer(typeof(T)).Deserialize(xw);
}

6

इस सवाल पर सबसे लंबे समय तक चलने वाला सबसे विशिष्ट दृष्टिकोण है: पृथक भंडारण।

एक्सएमएल या किसी अन्य प्रारूप में अपने नियंत्रण राज्य को सीरियलाइज़ करें (विशेष रूप से आसानी से यदि आप WPF के साथ निर्भरता गुणों को बचा रहे हैं), तो फ़ाइल को उपयोगकर्ता के पृथक भंडारण में सहेजें।

यदि आप एप्लिकेशन सेटिंग मार्ग पर जाना चाहते हैं, तो मैंने स्वयं एक बिंदु पर कुछ ऐसा ही करने की कोशिश की ... हालांकि नीचे के दृष्टिकोण को पृथक भंडारण का उपयोग करने के लिए आसानी से अनुकूलित किया जा सकता है:

class SettingsManager
{
    public static void LoadSettings(FrameworkElement sender, Dictionary<FrameworkElement, DependencyProperty> savedElements)
    {
        EnsureProperties(sender, savedElements);
        foreach (FrameworkElement element in savedElements.Keys)
        {
            try
            {
                element.SetValue(savedElements[element], Properties.Settings.Default[sender.Name + "." + element.Name]);
            }
            catch (Exception ex) { }
        }
    }

    public static void SaveSettings(FrameworkElement sender, Dictionary<FrameworkElement, DependencyProperty> savedElements)
    {
        EnsureProperties(sender, savedElements);
        foreach (FrameworkElement element in savedElements.Keys)
        {
            Properties.Settings.Default[sender.Name + "." + element.Name] = element.GetValue(savedElements[element]);
        }
        Properties.Settings.Default.Save();
    }

    public static void EnsureProperties(FrameworkElement sender, Dictionary<FrameworkElement, DependencyProperty> savedElements)
    {
        foreach (FrameworkElement element in savedElements.Keys)
        {
            bool hasProperty =
                Properties.Settings.Default.Properties[sender.Name + "." + element.Name] != null;

            if (!hasProperty)
            {
                SettingsAttributeDictionary attributes = new SettingsAttributeDictionary();
                UserScopedSettingAttribute attribute = new UserScopedSettingAttribute();
                attributes.Add(attribute.GetType(), attribute);

                SettingsProperty property = new SettingsProperty(sender.Name + "." + element.Name,
                    savedElements[element].DefaultMetadata.DefaultValue.GetType(), Properties.Settings.Default.Providers["LocalFileSettingsProvider"], false, null, SettingsSerializeAs.String, attributes, true, true);
                Properties.Settings.Default.Properties.Add(property);
            }
        }
        Properties.Settings.Default.Reload();
    }
}

.....तथा....

  Dictionary<FrameworkElement, DependencyProperty> savedElements = new Dictionary<FrameworkElement, DependencyProperty>();

public Window_Load(object sender, EventArgs e) {
           savedElements.Add(firstNameText, TextBox.TextProperty);
                savedElements.Add(lastNameText, TextBox.TextProperty);

            SettingsManager.LoadSettings(this, savedElements);
}

private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            SettingsManager.SaveSettings(this, savedElements);
        }

5

डेटाबेस के अलावा, उपयोगकर्ता से संबंधित सेटिंग्स को सहेजने के लिए आपके पास निम्न विकल्प भी हो सकते हैं

  1. के तहत रजिस्ट्री HKEY_CURRENT_USER

  2. AppDataफ़ोल्डर में एक फ़ाइल में

  3. SettingsWPF में फ़ाइल का उपयोग करना और उपयोगकर्ता के रूप में इसका दायरा निर्धारित करना


2
सुझाव 1 यही कारण है कि अनुप्रयोग विंडोज को धीमा कर देते हैं, बेहतर नहीं है कि किसी फ़ाइल IMO में बेहतर तरीके से रजिस्ट्री कुंजियों को भरें।
सांत्वना

1
@Console, डिस्क पर फ़ाइल को धीमा करना (पहनना बंद करना) SSD, डेटाबेस में डेटा लिखने से डेटाबेस धीमा हो जाता है। फिर आपका क्या विकल्प है? विंडोज़ रजिस्ट्री को सेटिंग्स को बचाने के लिए एक स्थान के रूप में उपयोग करने का इरादा है ।
सिनैट्रर

1
आप सही हैं, मुझे लगता है कि यह उल्लेख करना महत्वपूर्ण है कि रजिस्ट्री में कुछ कमियां हैं अगर हर आवेदन वहाँ उपयोगकर्ता की वरीयताओं को बचाता है।
सांत्वना

@Sinatr मूल रूप से, रजिस्ट्री का उद्देश्य उस उद्देश्य के लिए था ... लेकिन यह बड़ी मात्रा में डेटा को संभालने के लिए डिज़ाइन नहीं किया गया था, इसलिए इतिहास के कुछ बिंदु पर, Microsoft ने इसका उपयोग बंद करने की सिफारिश की है। जहाँ तक मुझे पता है, Windows पूरी रजिस्ट्री को लॉगऑन पर लोड करता है और साथ ही रोमिंग के लिए कॉपी भी करेगा या किसी बड़ी दुर्घटना के बाद अंतिम ज्ञात अच्छे कॉन्फ़िगरेशन को लोड करने में सक्षम होगा। इस प्रकार रजिस्ट्री का उपयोग करने से सिस्टम प्रभावित होता है भले ही एप्लिकेशन का उपयोग कभी न किया गया हो।
Phil1970

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

3

मेरे अनुभव में डेटाबेस तालिका में सभी सेटिंग्स को संग्रहीत करना सबसे अच्छा समाधान है। प्रदर्शन के बारे में भी चिंता मत करो। आज के डेटाबेस तेज़ हैं और आसानी से एक तालिका में हजारों कॉलम संग्रहीत कर सकते हैं। मैंने इसे कठिन तरीके से सीखा - इससे पहले कि मैं सीरमलाइज़ / डिसरियालाइज़ कर रहा था - दुःस्वप्न। इसे स्थानीय फ़ाइल या रजिस्ट्री में संग्रहीत करने में एक बड़ी समस्या है - अगर आपको अपने ऐप का समर्थन करना है और कंप्यूटर बंद है - उपयोगकर्ता इसके सामने नहीं है - ऐसा कुछ भी नहीं है जो आप कर सकते हैं .... अगर सेट डीबी में हैं - तो आप कर सकते हैं उन्हें और वायोला को यह उल्लेख करने के लिए नहीं बदला कि आप सेटिंग्स की तुलना कर सकते हैं ...।


और उन्हें दूर से संग्रहीत करना भी एक बड़ी समस्या है जब कनेक्शन उपलब्ध नहीं है ... ऑनलाइन काम करने के लिए लिखे गए कई अनुप्रयोगों में ऑफ़लाइन काम करते समय आदर्श अनुभव से कम है या कभी-कभी बग भी होते हैं जो ऑफ़लाइन होने पर भी काम न करने के लिए कुछ कार्यक्षमता बनाते हैं। "जासूसी" के अलावा कोई प्रभाव नहीं है कि डिवाइस का उपयोग कैसे किया जाता है।
Phil1970

1

मैं आमतौर पर एक कस्टम [ Serializable] सेटिंग वर्ग को परिभाषित करके और डिस्क पर क्रमबद्ध करके इस तरह का काम करता हूं । आपके मामले में आप इसे आसानी से अपने SQLite डेटाबेस में एक स्ट्रिंग ब्लॉब के रूप में संग्रहीत कर सकते हैं।


0
  1. मेरे द्वारा काम किए गए सभी स्थानों में, एप्लिकेशन समर्थन के कारण डेटाबेस अनिवार्य हो गया है। जैसा कि एडम ने कहा, उपयोगकर्ता अपने डेस्क पर नहीं हो सकता है या मशीन बंद हो सकती है, या आप जल्दी से किसी के कॉन्फ़िगरेशन को बदलना चाहते हैं या नए-जॉइनर को डिफ़ॉल्ट (या टीम के सदस्य के) कॉन्फिगर असाइन कर सकते हैं।

  2. यदि सेटिंग के बढ़ने की संभावना है, क्योंकि एप्लिकेशन के नए संस्करण जारी किए जाते हैं, तो आप डेटा को ब्लॉब्स के रूप में संग्रहित करना चाह सकते हैं, जिसे तब एप्लिकेशन द्वारा डीसर्विलाइज़ किया जा सकता है। यह विशेष रूप से उपयोगी है यदि आप प्रिज्म जैसी किसी चीज का उपयोग करते हैं जो मॉड्यूल को रोकता है, क्योंकि आप यह नहीं जान सकते हैं कि मॉड्यूल क्या सेटिंग्स वापस करेगा। ब्लॉब्स को उपयोगकर्ता नाम / मशीन कम्पोजिट कुंजी द्वारा कुंजीबद्ध किया जा सकता है। इस तरह से आप हर मशीन के लिए अलग-अलग सेटिंग्स रख सकते हैं।

  3. मैंने इन-बिल्ट सेटिंग्स क्लास का उपयोग नहीं किया है, इसलिए मैं टिप्पणी करने से बचूंगा। :)


0

मैं अपने VB.net डेस्कटॉप WPF एप्लिकेशन के लिए एक वर्ग पर आधारित एक xml नियंत्रण फ़ाइल का उपयोग करना चाहता था। उपरोक्त कोड यह सब करने के लिए उत्कृष्ट है और मुझे सही दिशा में सेट करता है। यदि कोई VB.net समाधान के लिए खोज कर रहा है तो यहां वह वर्ग है जिसे मैंने बनाया है:

Imports System.IO
Imports System.Xml.Serialization

Public Class XControl

Private _person_ID As Integer
Private _person_UID As Guid

'load from file
Public Function XCRead(filename As String) As XControl
    Using sr As StreamReader = New StreamReader(filename)
        Dim xmls As New XmlSerializer(GetType(XControl))
        Return CType(xmls.Deserialize(sr), XControl)
    End Using
End Function

'save to file
Public Sub XCSave(filename As String)
    Using sw As StreamWriter = New StreamWriter(filename)
        Dim xmls As New XmlSerializer(GetType(XControl))
        xmls.Serialize(sw, Me)
    End Using
End Sub

'all the get/set is below here

Public Property Person_ID() As Integer
    Get
        Return _person_ID
    End Get
    Set(value As Integer)
        _person_ID = value
    End Set
End Property

Public Property Person_UID As Guid
    Get
        Return _person_UID
    End Get
    Set(value As Guid)
        _person_UID = value
    End Set
End Property

End Class
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.