سؤال

أنا أحاول لتنفيذ تحميل / حفظ وظيفة تطبيق نماذج Windows.

لقد حصلت على المكونات التالية:

  • طريقة عرض شجرة
  • زوجين من قائمة وجهات النظر
  • بضعة مربعات النص
  • اثنين من الكائنات (التي يحمل كبيرة dictionarylist)

أريد أن تنفيذ طريقة حفظ كل هذا في ملف السيرة الذاتية/تحميل في وقت لاحق.

ما هي أفضل طريقة للقيام بذلك ؟

أعتقد XML التسلسل هو الطريق للذهاب ، ولكن لست متأكدا تماما كيف أو من أين تبدأ.أو أنها سوف تتطلب حقا الحل أن تكون قادرة على القيام بذلك ؟

هل كانت مفيدة؟

المحلول

هنا مثال الذي يربط كائن وبعض الأجداد واجهة المستخدم;استخدام C# 3.0 هنا هو محض الإيجاز - كل شيء سوف تعمل مع C# 2.0 أيضا.

معظم الرمز هنا هو إعداد النموذج ، و/أو التعامل مع الممتلكات-تغيير الإخطارات - الأهم من ذلك, ليس هناك أي قانون يكرس تحديث واجهة المستخدم من نموذج كائن أو كائن نموذج من واجهة المستخدم.

نلاحظ أيضا IDE يمكن أن تفعل الكثير من ربط البيانات رمز لك ببساطة عن طريق إسقاط BindingSource على نموذج تحديد مصدر البيانات إلى نوع via الحوار في الممتلكات الشبكة.

لاحظ أنه ليس من الضروري توفر خاصية تغيير الإخطارات (إن PropertyChanged الاشياء) - ومع ذلك ، أكثر 2-الطريقة واجهة المستخدم ملزم سوف تعمل أفضل بكثير إذا قمت بتطبيق هذا.لا أن PostSharp بعض طرق مثيرة للاهتمام للقيام بذلك مع الحد الأدنى من التعليمات البرمجية.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Windows.Forms;
using System.Xml.Serialization;
static class Program { // formatted for vertical space
    [STAThread]
    static void Main() {
        Application.EnableVisualStyles();

        Button load, save, newCust;
        BindingSource source = new BindingSource { DataSource = typeof(Customer) };
        XmlSerializer serializer = new XmlSerializer(typeof(Customer));
        using (Form form = new Form {
            DataBindings = {{"Text", source, "Name"}}, // show customer name as form title
            Controls = {
                new DataGridView { Dock = DockStyle.Fill, // grid of orders
                    DataSource = source, DataMember = "Orders"},
                new TextBox { Dock = DockStyle.Top, ReadOnly = true, // readonly order ref
                    DataBindings = {{"Text", source, "Orders.OrderRef"}}},
                new TextBox { Dock = DockStyle.Top, // editable customer name
                    DataBindings = {{"Text", source, "Name"}}},
                (save = new Button { Dock = DockStyle.Bottom, Text = "save" }),
                (load = new Button{ Dock = DockStyle.Bottom, Text = "load"}),
                (newCust = new Button{ Dock = DockStyle.Bottom, Text = "new"}),   
            }
        })
        {
            const string PATH = "customer.xml";
            form.Load += delegate {
                newCust.PerformClick(); // create new cust when loading form
                load.Enabled = File.Exists(PATH);
            };
            save.Click += delegate {
                using (var stream = File.Create(PATH)) {
                    serializer.Serialize(stream, source.DataSource);
                }
                load.Enabled = true;
            };
            load.Click += delegate {
                using (var stream = File.OpenRead(PATH)) {
                    source.DataSource = serializer.Deserialize(stream);
                }
            };
            newCust.Click += delegate {
                source.DataSource = new Customer();
            };
            Application.Run(form);
        } 
    }
}

[Serializable]
public sealed class Customer : NotifyBase {
    private int customerId;
    [DisplayName("Customer Number")]
    public int CustomerId {
        get { return customerId; }
        set { SetField(ref customerId, value, "CustomerId"); }
    }

    private string name;
    public string Name {
        get { return name; }
        set { SetField(ref name, value, "Name"); }
    }

    public List<Order> Orders { get; set; } // XmlSerializer demands setter

    public Customer() {
        Orders = new List<Order>();
    }
}

[Serializable]
public sealed class Order : NotifyBase {
    private int orderId;
    [DisplayName("Order Number")]
    public int OrderId  {
        get { return orderId; }
        set { SetField(ref orderId, value, "OrderId"); }
    }

    private string orderRef;
    [DisplayName("Reference")]
    public string OrderRef {
        get { return orderRef; }
        set { SetField(ref orderRef, value, "OrderRef"); }
    }

    private decimal orderValue, carriageValue;

    [DisplayName("Order Value")]
    public decimal OrderValue {
        get { return orderValue; }
        set {
            if (SetField(ref orderValue, value, "OrderValue")) {
                OnPropertyChanged("TotalValue");
            }
        }
    }

    [DisplayName("Carriage Value")]
    public decimal CarriageValue {
        get { return carriageValue; }
        set {
            if (SetField(ref carriageValue, value, "CarriageValue")) {
                OnPropertyChanged("TotalValue");
            }
        }
    }

    [DisplayName("Total Value")]
    public decimal TotalValue { get { return OrderValue + CarriageValue; } }
}

[Serializable]
public class NotifyBase { // purely for convenience
    [field: NonSerialized]
    public event PropertyChangedEventHandler PropertyChanged;

    protected bool SetField<T>(ref T field, T value, string propertyName) {
        if (!EqualityComparer<T>.Default.Equals(field, value)) {
            field = value;
            OnPropertyChanged(propertyName);
            return true;
        }
        return false;
    }
    protected virtual void OnPropertyChanged(string propertyName) {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

نصائح أخرى

من الناحية المثالية, يجب أن لا يكون استمرار واجهة المستخدم الدولة ؛ يجب أن يكون استمرار الدولة من بعض وجوه نموذج يمثل البيانات الخاصة بك.مع استثناء من TreeView, هو إلى حد ما تافهة استخدام ربط البيانات إلى التعادل طراز كائن إلى واجهة المستخدم.هذا يمكن أن يكون إما DataTable-نهج أو فئة مخصصة الهرمي (أفضله).

مرة واحدة كنت قد فصل البيانات من واجهة المستخدم, حفظ البيانات بسيطة.هناك الكثير من الأمثلة XmlSerializer الخ.

نعم ، يجب عليك بالتأكيد استخدام XML التسلسل على هذا.ولكن مارك Gravell لاحظ يجب أن يكون لديك الأشياء التي تحمل البيانات المعروضة من خلال واجهة المستخدم الرسومية المكونات الأولى.ثم يمكنك عمليا جعل (دي)التسلسل التلقائي, مع الحد الأدنى من الأسطر من التعليمات البرمجية.

هناك مشكلة مع عينة أعلاه.نعتبر أن في نهاية المطاف التطبيق الخاص بك يتم تحديث.وجوه الخاص بك نموذج يمكن أن تغير جذريا وبالتالي فإنه لا يمكن الحصول على إلغاء تسلسل.هناك بعض الأشياء التي يمكن القيام به لضمان أن إلغاء التسلسل من xml version 1 يمكن إلغاء تسلسل إلى طراز كائن في الإصدار 2 ولكن إذا كان هناك احتمال أنه يمكن أن يكون كبير التغييرات الهيكلية xml إلغاء التسلسل هو لا الطريق للذهاب.

إذا كان هذا هو الحال و نشر التطبيق للعملاء أود أن أقترح بشدة أن تأخذ نظرة أخرى في حفظ/تحميل المنطق.

Versionized التسلسل/إلغاء التسلسل
تسلسل الكائن الدولة في شكل:

<ObjectState version="1">
    <Field1>value</Field1>
    ... etc ...
</ObjectState>

حتى الآن لديك نسخة من نموذج كائن التي ولدت الدولة حفظها.في إلغاء التسلسل يمكنك أن تأخذ القياسات الخاصة لاستيعاب هذا الواقع.على سبيل المثال كتابة field1 ومن القيمة في قائمة في بعض وجوه أخرى.

وثمة نهج آخر هو:

Versionized التسلسل و التحويل قبل إلغاء التسلسل
تسلسل الكائن الدولة كما ذكر أعلاه (مع نسخة السمة).
عندما تسلسل نظرة على الإصدار السمة إذا لم تكن هذه هي النسخة تتوقع تحويل تسلسل كائن الدولة مع xsl-البرامج النصية أو التعليمات البرمجية c# إلى الإصدار الحالي.يمكنك حفظ قائمة تحويلات xsl في المشروع الحالي

- conversions
    - v1-v2
    - v2-v3

إذا كنت حاليا في الإصدار 3 و تريد تحميل ملف xml الخاص بك نظرة على الإصدار السمة وتشغيل جميع xsl البرامج النصية للحصول على الإصدار الحالي (الإصدار 3).إذا كنت تشغيل xsl-script v1-v2 وبعد ذلك v2-v3.

في هذه الحالة هل يمكن أن يكون طبيعي التسلسل وإلغاء التسلسل الفئات التي لا يجب أن نهتم الوراء القدرة.

فمن تافهة إلى حد ما للاستخدام ربط البيانات لربط كائن نموذج واجهة المستخدم.

كيف يمكنني ربط كائن مع واجهة المستخدم الرسومية السيطرة دون استمرار التخزين ؟ إذا كنت تفعل ذلك يدويا يعني أن علي أن أكتب كمية سخيفة من رمز لكل كائن واحد في الذاكرة.أنا بالفعل نوعا من فئة تخزين هذه البيانات لكنه لا ربط نوع السيناريو هو مثل قراءة هذه الكتابة هنا.

يفترض بي أن أكتب المحمل الذي يحمل تسلسل XML و الحصول على كائن ومن ثم قراءة موضوع تملأ كل GUI ؟ ومن الواضح أن هذا أشبه التحميل اليدوي غير ملزمة.أنا في عداد المفقودين شيئا ؟

هنا هو مقال رائع حول كيفية جعل الخاص بك فئة أو البنية قابل للتسلسل.وأود أن إنشاء فئة من شأنها أن تسمح لك لتخزين جميع البيانات التي ترغب في ذلك.جعل الطبقة serialable.هذه الطريقة فقط بضعة أسطر من التعليمات البرمجية يمكنك حفظ جميع البيانات الخاصة بك إلى ملف.ثم مع فقط بضعة أسطر من التعليمات البرمجية يمكنك استرداد البيانات من الملف.

http://www.codeproject.com/KB/cs/objserial.aspx

بديل التسلسلية الفصول الدراسية هو استخدام أحد ADO.NET بيانات لتخزين البيانات التي بنيت في مرافق المستمرة إلى ملف XML.كود سوف يكون الحد الأدنى, و يمكنك تخزين فقط البيانات ذات الصلة التي تحتاجها من خلال تصميم الجداول التي تناسب نموذج العملية التي تقوم بها.بالإضافة إلى ذلك, سوف تكون قادرة على استخدام نفس التعليمات البرمجية إذا كنت ترغب في وقت لاحق تستمر حالة واجهة المستخدم إلى قاعدة البيانات بدلا من ملف محلي.كنت فقط بحاجة إلى بديل وظيفة حفظ البيانات.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top