ฉันจะบันทึกการตั้งค่าแอปพลิเคชันในแอปพลิเคชัน Windows Forms ได้อย่างไร


582

สิ่งที่ฉันต้องการบรรลุนั้นง่ายมาก: ฉันมีแอปพลิเคชัน Windows Forms (.NET 3.5) ที่ใช้พา ธ สำหรับการอ่านข้อมูล เส้นทางนี้สามารถแก้ไขได้โดยผู้ใช้โดยใช้แบบฟอร์มตัวเลือกที่ฉันมีให้

ตอนนี้ฉันต้องการบันทึกค่าพา ธ ไปยังไฟล์เพื่อใช้ในภายหลัง นี่จะเป็นการตั้งค่าที่บันทึกไว้ในไฟล์นี้ ไฟล์นี้จะอยู่ในโฟลเดอร์แอปพลิเคชันโดยตรง

ฉันเข้าใจว่ามีสามตัวเลือก:

  • ไฟล์ ConfigurationSettings (appname.exe.config)
  • Registry
  • ไฟล์ XML ที่กำหนดเอง

ฉันอ่านว่าไฟล์การกำหนดค่า. NET ไม่ได้เล็งเห็นถึงการบันทึกค่ากลับคืนมา ในส่วนของรีจิสตรี้ผมอยากจะให้ไกลที่สุดเท่าที่จะทำได้

นี่หมายความว่าฉันควรใช้ไฟล์ XML ที่กำหนดเองเพื่อบันทึกการตั้งค่าหรือไม่

ถ้าเป็นเช่นนั้นฉันต้องการดูตัวอย่างโค้ดของ (C #)

ฉันเคยเห็นการสนทนาอื่นในเรื่องนี้ แต่ก็ยังไม่ชัดเจนสำหรับฉัน


นี่เป็นแอปพลิเคชั่น. NET WinForms หรือไม่? ถ้าเป็นเช่นนั้นคุณกำลังพัฒนา. NET เวอร์ชันใดอยู่?
พอร์ตแมน

1
ใช่มันเป็นแอปพลิเคชั่น. NET Framework เวอร์ชั่น 3.5 WinForms
Fueled

1
คุณต้องการบันทึกรหัสผ่านหรือค่าความลับหรือไม่ อาจต้องใช้การเข้ารหัส
Kiquenet

คำตอบ:


593

ถ้าคุณทำงานกับ Visual Studio มันเป็นเรื่องง่ายที่จะได้รับการตั้งค่าแบบถาวร คลิกขวาที่โครงการในโซลูชัน Explorer และเลือกคุณสมบัติ เลือกแท็บการตั้งค่าและคลิกที่ไฮเปอร์ลิงก์หากไม่มีการตั้งค่า

ใช้แท็บการตั้งค่าเพื่อสร้างการตั้งค่าแอปพลิเคชัน 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 และโครงการประเภทอื่น ๆ

โปรดทราบว่าคุณต้องตั้งค่าคุณสมบัติขอบเขตของการตั้งค่าของคุณ หากคุณเลือกขอบเขตแอปพลิเคชันแล้ว Settings.Default <คุณสมบัติของคุณ> จะเป็นแบบอ่านอย่างเดียว

การอ้างอิง: วิธีการ: เขียนการตั้งค่าผู้ใช้ ณ รันไทม์ด้วย C # - Microsoft Docs


2
ถ้าฉันมีวิธีแก้ปัญหาสิ่งนี้จะใช้กับโซลูชันทั้งหมดหรือสำหรับแต่ละโครงการหรือไม่
franko_camron

8
@ สี่: ฉันมีโครงการ. NET 4.0 WinApp ที่นี่และคุณสมบัติบางอย่างของฉันไม่ได้อ่านอย่างเดียว Settings.Default.SomeProperty = 'value'; Settings.Default.Save();ทำงานเหมือนจับใจ หรือเป็นเพราะฉันมีการตั้งค่าผู้ใช้?
doekman

4
@ สี่: เมื่อฉันเปลี่ยนการตั้งค่าจากผู้ใช้เป็นขอบเขตแอปพลิเคชันและบันทึกไฟล์ฉันเห็นในโค้ดที่สร้างขึ้นซึ่งผู้ตั้งค่าได้หายไป สิ่งนี้จะเกิดขึ้นกับโปรไฟล์ลูกค้า 4.0 ...
doekman

3
@ สี่: ลิงค์ที่ดีแม้ว่าคำสั่งของคุณว่าSettings.Default.Save()ไม่มีอะไรไม่ถูกต้อง ในฐานะที่เป็นรัฐ @aku ในคำตอบการตั้งค่าขอบเขตแอพเป็นแบบอ่านอย่างเดียว: การบันทึกจะไม่มีประสิทธิภาพสำหรับพวกเขา ใช้PortableSettingsProvider แบบกำหนดเองนั้นเพื่อบันทึกการตั้งค่าขอบเขตผู้ใช้ไปยัง app.config ที่ซึ่ง exe อยู่แทนที่จะเป็นหนึ่งในโฟลเดอร์ AppData ของผู้ใช้ ไม่ไม่ดี แต่ฉันใช้มันในระหว่างการพัฒนาเพื่อใช้การตั้งค่าเดียวกันจากการคอมไพล์ไปยังคอมไพล์ (โดยไม่มีมันจะไปโฟลเดอร์ผู้ใช้ใหม่ที่ไม่ซ้ำกับคอมไพล์แต่ละรายการ)
minnow

7
ณ ตอนนี้ด้วย. NET 3.5 จะปรากฏขึ้นคุณสามารถใช้ Settings.Default.SomeProperty เพื่อกำหนดค่าและรับ typecasting ที่แข็งแกร่ง นอกจากนี้เพื่อประหยัดเวลาผู้อื่น (ใช้เวลาสักครู่ในการคิดสิ่งนี้) คุณต้องพิมพ์ Properties.Settings.Default หรือเพิ่มโดยใช้ YourProjectNameSpace.Settings ที่ด้านบนของไฟล์ของคุณ ไม่พบคำว่า "การตั้งค่า" เพียงอย่างเดียว
eselk

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 เป็นพา ธ สัมบูรณ์หากคุณต้องการบันทึกลงในไดเรกทอรีอื่น ฉันคิดว่าเป็นเรื่องธรรมดาที่สุดที่จะบันทึกไฟล์ไว้ในไดเรกทอรีเดียวกับแอปพลิเคชันหรือไดเรกทอรีย่อยหากคุณไม่ได้บันทึกไว้ในรีจิสทรี
เทรเวอร์

โอ้บางทีตัวเลือกที่ดีกว่าคือการจัดเก็บไฟล์การตั้งค่าในโฟลเดอร์ appdata ของผู้ใช้
เทรเวอร์

1
ไม่จำเป็นต้องเปลี่ยนDEFAULT_FILENAMEเพียงโทรsettings.Save(theFileToSaveTo); เป็นพิมพ์ใหญ่ทั้งหมดDEFAULT_FILENAMEควรจะเป็นอย่างต่อเนื่อง DEFAULT_FILENAMEถ้าคุณต้องการคุณสมบัติอ่านเขียนให้หนึ่งและมีการสร้างตั้งค่าให้ จากนั้นให้ค่าอาร์กิวเมนต์เริ่มต้นnullคือทดสอบและใช้คุณสมบัติของคุณเป็นค่าเริ่มต้น มันพิมพ์ได้อีกเล็กน้อย แต่ให้อินเทอร์เฟซมาตรฐานมากขึ้น
Jesse Chisholm

10
คุณจะต้องอ้างอิงSystem.Web.Extensions.dllหากยังไม่ได้ดำเนินการ
TEK

9
ฉันได้สร้างห้องสมุดทั้งหมดตามคำตอบนี้พร้อมการปรับปรุงมากมายและทำให้มันพร้อมใช้งานใน nuget: github.com/Nucs/JsonSettings
NucS

67

รีจิสทรีไม่ต้องดำเนินการ คุณไม่แน่ใจว่าผู้ใช้ที่ใช้แอปพลิเคชันของคุณมีสิทธิ์เพียงพอที่จะเขียนลงในรีจิสทรีหรือไม่

คุณสามารถใช้app.configไฟล์เพื่อบันทึกการตั้งค่าระดับแอปพลิเคชัน (เหมือนกันสำหรับผู้ใช้แต่ละคนที่ใช้แอปพลิเคชันของคุณ)

ฉันจะเก็บการตั้งค่าเฉพาะผู้ใช้ในไฟล์ XML ซึ่งจะถูกบันทึกไว้ในIsolated StorageหรือในไดเรกทอรีSpecialFolder.ApplicationData

ถัดจากนั้นมาจาก. NET 2.0 มันเป็นไปได้ที่จะเก็บค่ากลับไปที่app.configไฟล์


8
ใช้รีจิสตรีหากคุณต้องการการตั้งค่าสำหรับการเข้าสู่ระบบ / ผู้ใช้แต่ละครั้ง
thenonhacker

19
รีจิสทรีไม่ใช่พอร์ต
Kb

10
@thenonhacker: หรือใช้ Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData)
Kenny Mann

4
สามารถเขียนรีจีสทรีผู้ใช้ไปที่ (มีโปรแกรมจำนวนมากเขียนข้อมูลอยู่ที่นั่น ข้อดีของการใช้การตั้งค่ารีจิสทรีโดยใช้การตั้งค่าคือถ้าคุณมีหลายแอปพลิเคชั่นที่แชร์โฟลเดอร์เดียวกัน (เช่นโปรแกรมติดตั้งและโปรแกรมแอปพลิเคชัน) พวกเขาจะไม่แชร์การตั้งค่าเดียวกัน
Kesty

3
ข้อเสียเปรียบหลักของ Registry คือวิธีที่ยากในการส่งออก / คัดลอกการตั้งค่าไปยังพีซีเครื่องอื่น แต่ฉันไม่เห็นด้วยกับ "คุณไม่แน่ใจว่าผู้ใช้ที่ใช้แอปพลิเคชันของคุณมีสิทธิ์เพียงพอที่จะเขียนลงทะเบียน" - ใน HKEY_CURRENT_USER คุณมีสิทธิ์ในการเขียนเสมอ มันสามารถปฏิเสธได้ แต่ระบบไฟล์ยังไม่สามารถเข้าถึงได้สำหรับผู้ใช้ปัจจุบัน (โฟลเดอร์ TEMP ที่เป็นไปได้ทั้งหมด ฯลฯ )
i486

20

ApplicationSettingsระดับไม่สนับสนุนการตั้งค่าประหยัดไปapp.configไฟล์ นั่นเป็นอย่างมากจากการออกแบบ แอปพลิเคชันที่ทำงานด้วยบัญชีผู้ใช้ที่ปลอดภัย (คิดว่า Vista UAC) ไม่มีสิทธิ์ในการเขียนไปยังโฟลเดอร์การติดตั้งของโปรแกรม

คุณสามารถต่อสู้กับระบบด้วยConfigurationManagerคลาส แต่วิธีแก้ปัญหาเล็กน้อยคือเข้าไปที่ตัวออกแบบการตั้งค่าและเปลี่ยนขอบเขตของการตั้งค่าเป็นผู้ใช้ หากนั่นเป็นสาเหตุของความยากลำบาก (กล่าวคือการตั้งค่านั้นเกี่ยวข้องกับผู้ใช้ทุกคน) คุณควรวางคุณสมบัติตัวเลือกของคุณไว้ในโปรแกรมแยกต่างหากเพื่อให้คุณสามารถขอพรอมต์การยกระดับสิทธิ์ หรือสละสิทธิ์ใช้การตั้งค่า


คุณช่วยขยายความในประโยคสุดท้ายของคุณได้ไหม? ขอระดับความสูงเพื่อเขียน app.config หรือเขียนแอปพลิเคชันแยกต่างหากซึ่งจะผ่านผู้ใช้ในบ้านทั้งหมดของผู้ใช้มองหา user.config และแก้ไขสิ่งเหล่านี้หรือไม่
CannibalSmith

2
โปรแกรมแยกต่างหากต้องการรายการเพื่อขอยกระดับ Google 'asinvoker ต้องการผู้ดูแลระบบ' เพื่อค้นหาไวยากรณ์ที่เหมาะสม การแก้ไข user.config นั้นใช้ไม่ได้และไม่จำเป็น
46919 Hans Passant

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

ฉันต้องการแชร์ห้องสมุดที่ฉันสร้างขึ้นเพื่อสิ่งนี้ มันเป็นห้องสมุดเล็ก ๆ แต่มีการปรับปรุงใหญ่ (IMHO) มากกว่าไฟล์. setset

ห้องสมุดที่เรียกว่าJot (GitHub) นี่คือบทความ The Code Projectเก่าที่ฉันเขียนเกี่ยวกับเรื่องนี้

นี่คือวิธีที่คุณจะใช้เพื่อติดตามขนาดและตำแหน่งของหน้าต่าง:

public MainWindow()
{
    InitializeComponent();

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

ผลประโยชน์เมื่อเทียบกับไฟล์ .settings:มีรหัสมากน้อยเป็นและมันมากน้อยผิดพลาดได้ง่ายเนื่องจากคุณจะต้องพูดถึงสถานที่ให้บริการในแต่ละครั้งเดียว

ด้วยไฟล์การตั้งค่าคุณต้องพูดถึงคุณสมบัติแต่ละครั้งห้าครั้ง: เมื่อคุณสร้างคุณสมบัติอย่างชัดเจนและเพิ่มอีกสี่ครั้งในรหัสที่คัดลอกค่าไปมา

ที่เก็บข้อมูลการทำให้เป็นอนุกรม ฯลฯ สามารถกำหนดค่าได้อย่างสมบูรณ์ เมื่อวัตถุเป้าหมายถูกสร้างขึ้นโดยคอนเทนเนอร์IoCคุณสามารถ [เชื่อมต่อ] [] เพื่อให้สามารถใช้การติดตามโดยอัตโนมัติกับวัตถุทั้งหมดที่แก้ไขเพื่อให้สิ่งที่คุณต้องทำเพื่อให้คุณสมบัติคงอยู่คือการตบ [ติดตามได้] คุณลักษณะที่มัน

สามารถกำหนดค่าได้อย่างสูงและคุณสามารถกำหนดค่า: - เมื่อข้อมูลถูกเก็บถาวรและนำไปใช้ทั่วโลกหรือสำหรับแต่ละวัตถุที่ถูกติดตาม - วิธีการเรียงลำดับ - ที่จัดเก็บ (เช่นไฟล์ฐานข้อมูลออนไลน์ที่เก็บข้อมูลแยกต่างหากรีจิสทรี) - กฎที่สามารถยกเลิกการใช้ / ข้อมูลที่ยังคงอยู่สำหรับคุณสมบัติ

เชื่อฉันสิห้องสมุดแห่งนี้ยอดเยี่ยมมาก!


14

วิธีง่ายๆคือใช้วัตถุข้อมูลการกำหนดค่าบันทึกเป็นไฟล์ XML พร้อมชื่อแอปพลิเคชันในโฟลเดอร์ในเครื่องและเมื่อเริ่มต้นอ่านกลับ

นี่คือตัวอย่างในการจัดเก็บตำแหน่งและขนาดของแบบฟอร์ม

dataobject การกำหนดค่าถูกพิมพ์อย่างยิ่งและใช้งานง่าย:

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

1
ฉันใช้งานได้ดีในการพัฒนา แต่เมื่อฉันปรับใช้แอปพลิเคชันผู้ใช้โดยเฉลี่ยจะไม่สามารถเข้าถึงc:\program files\my applicationโฟลเดอร์ได้ดังนั้นการบันทึกการตั้งค่าจึงเกิดข้อผิดพลาด ฉันกำลังมองหาการบันทึกไฟล์ xml ใน AppData แทน แต่ฉันแค่สงสัยว่ามีวิธีที่ชัดเจนในการแก้ไขปัญหานี้หรือไม่เนื่องจากวิธีการนี้ดูเหมือนจะได้ผลสำหรับคุณ
Philip Stratford

@PhilipStratford เนื่องจากเป็นไฟล์ปกติคุณจึงสามารถบันทึกได้ทุกที่ เพียงค้นหาสถานที่ที่มีการเข้าถึงเพื่อเขียน
Dieter Meemken

@PhilipStratford อาจจะเป็นโฟลเดอร์ AppData เป็นตัวเลือกสำหรับคุณดูC # ได้รับเส้นทางของ% AppData%ดังกล่าวโดยว่าว
Dieter Meemken

ขอบคุณฉันใช้งานไปแล้วบันทึกไฟล์ xml ในโฟลเดอร์ AppDate ฉันเพิ่งสงสัยว่ามีวิธีที่ง่ายในการบันทึกลงในโฟลเดอร์ของแอปพลิเคชันตามตัวอย่างของคุณหรือไม่เนื่องจากฉันคิดว่าคุณทำให้มันใช้งานได้ ไม่ต้องกังวลโฟลเดอร์ AppData น่าจะเป็นตำแหน่งที่ดีกว่าอยู่แล้ว!
Philip Stratford


5

ตัวเลือกอื่นแทนการใช้ไฟล์ XML ที่กำหนดเองเราสามารถใช้รูปแบบไฟล์ที่เป็นมิตรกับผู้ใช้มากขึ้น: ไฟล์ JSON หรือ YAML

  • หากคุณใช้. NET 4.0 dynamic, ไลบรารีนี้ใช้งานง่าย (สนับสนุนซีเรียลไลซ์, ดีซีเรียลไลซ์ , วัตถุที่ซ้อนกันและสั่งซื้อเอาต์พุตตามที่คุณต้องการ + ผสานการตั้งค่าหลายรายการเข้ากับหนึ่ง) JsonConfig (การใช้งาน
  • สำหรับไลบรารีการตั้งค่า. 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 Forms ทำให้ง่ายต่อการสร้างจัดเก็บและบำรุงรักษาแอปพลิเคชันที่กำหนดเองและการตั้งค่าผู้ใช้บนคอมพิวเตอร์ไคลเอนต์ ด้วยการตั้งค่าแอปพลิเคชัน Windows Forms คุณสามารถจัดเก็บข้อมูลแอปพลิเคชันไม่เพียง แต่สตริงการเชื่อมต่อฐานข้อมูล แต่ยังรวมถึงข้อมูลเฉพาะผู้ใช้เช่นการตั้งค่าแอปพลิเคชันผู้ใช้ ด้วยการใช้ Visual Studio หรือรหัสที่จัดการเองคุณสามารถสร้างการตั้งค่าใหม่อ่านและเขียนลงดิสก์ผูกเข้ากับคุณสมบัติในแบบฟอร์มของคุณและตรวจสอบข้อมูลการตั้งค่าก่อนที่จะโหลดและบันทึก - http://msdn.microsoft.com/en-us/library/k4s6c3a0.aspx


2
ไม่จริง .. ดูคำตอบของ aku ด้านบน โดยใช้การตั้งค่าที่เป็นไปได้และ ApplicationSettingsBase
Gishu

2

บางครั้งคุณต้องการกำจัดการตั้งค่าเหล่านั้นที่เก็บไว้ในไฟล์ web.config หรือ app.config ดั้งเดิม คุณต้องการการควบคุมที่ละเอียดยิ่งขึ้นสำหรับการปรับใช้รายการการตั้งค่าของคุณและการออกแบบข้อมูลที่แยกจากกัน หรือความต้องการคือการเปิดใช้งานการเพิ่มรายการใหม่ที่รันไทม์

ฉันนึกได้สองทางเลือกที่ดี:

  • รุ่นที่พิมพ์อย่างยิ่งและ
  • รุ่นที่มุ่งเน้นวัตถุ

ข้อได้เปรียบของเวอร์ชันที่พิมพ์อย่างยิ่งคือชื่อและค่าที่ตั้งค่าไว้อย่างยิ่ง ไม่มีความเสี่ยงในการผสมชื่อหรือชนิดข้อมูล ข้อเสียคือต้องตั้งค่ารหัสเพิ่มเติมไม่สามารถเพิ่มได้ในขณะใช้งานจริง

ด้วยเวอร์ชันเชิงวัตถุข้อดีคือสามารถเพิ่มการตั้งค่าใหม่ได้ที่รันไทม์ แต่คุณไม่ได้พิมพ์ชื่อและค่าอย่างยิ่ง ต้องระวังด้วยตัวระบุสตริง ต้องทราบว่ามีการบันทึกชนิดข้อมูลไว้ก่อนหน้านี้เมื่อรับค่า

คุณสามารถค้นหารหัสการใช้งานของทั้งสองทำงานอย่างเต็มที่ที่นี่


2

ใช่เป็นไปได้ที่จะบันทึกการกำหนดค่า - แต่มันก็ขึ้นอยู่กับวิธีที่คุณเลือก ให้ฉันอธิบายความแตกต่างทางเทคนิคเพื่อให้คุณสามารถเข้าใจตัวเลือกที่คุณมี:

ครั้งแรกที่คุณต้องแยกความแตกต่างไม่ว่าคุณต้องการที่จะใช้applicationSettingsหรือAppSettingsในของคุณ*.exe.config(aka App.configไฟล์ใน Visual Studio) - มีความแตกต่างพื้นฐาน ถูกอธิบายไว้ที่นี่

ทั้งสองมีวิธีการบันทึกการเปลี่ยนแปลงที่แตกต่างกัน:

  • AppSettingsช่วยให้คุณสามารถอ่านและเขียนโดยตรงลงในไฟล์ config (ผ่าน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 - ยินดีต้อนรับดีใจที่ฉันสามารถช่วยคุณได้!
แมตต์

ดี! ในที่สุดคิดออกทั้งหมด Mom
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.