我试图实现一个装载/保存能用于Windows的形式应用程序。

我已经得到了以下部分组成:

  • 一棵树看
  • 几个列表中的风景
  • 几个文本的箱子
  • 一对夫妇的对象(其中有一个很大的dictionarylist)

我想要实现一种方式来保存所有此进入一个文件,并且恢复/加载。

什么是最好的方式做到这一点?

我认为XML化的路要走,但我不是很确定如何,或者从哪里开始。或将它需要一个非常复杂的解决方案能够这样做吗?

有帮助吗?

解决方案

这里有一个例子,结合对象和一些祖先 到UI;使用C#3.0在这里是纯粹是为了简洁起见- 一切都会的工作C#2.0。

大多数这里的代码是设置的形式,以及/或 处理财产的更改通知- 重要的是,没有任何代致力于更新 UI对象模型,或者对象的模型 UI。

还注意到IDE可以做很多的数据结合代码 对你,只是通过删除一个BindingSource到 形成和设置的数据源,以一种类型的通过 该对话在财产的网格。

注意,它不是必要的,以提供性的改变 通知(所引发的东西)-但是, 最2路UI结合将工作相当好 如果你这样做实现这一点。不,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));
    }
}

其他提示

理想的是,你不应该坚持UI状态;你应该坚持国家的一些对象模型代表了你的数据。除 TreeView, 它是相当微不足道的使用的数据结合配合对象模型的用户界面。这可能是一个 DataTable-基础的方法,或一定类层次(我的偏好)。

一旦你有分离的数据从用户界面,节省的数据是简单的。有很多例子 XmlSerializer 等等。

是的,你应该肯定使用XML化。但是,正如马克*Gravell指出,必须有目的持有的数据显示通过你闺组第一次。然后你几乎可以让(de)自动化,以最小的代码行。

有一个问题的样本上。考虑,最终应用程序是更新。你的对象模型可能发生急剧变化,因此它不能获得deserialized.有些事你可以做到确保一个反xml版本1可以deserialized到您的对象模型版本2但是,如果有可能,你可以有很大的结构变化的xml反的是 的路要走。

如果是这种情况,并应用程序部署到顾客我会强烈建议采取进一步的看看你的节省/载的逻辑。

Versionized化/反
serialize你的对象国家的形式:

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

所以现在你有版本的对象模型所产生的所保存的状态。在你的反可以采取特别的测量,以适应于这一事实。例如编写Field1价值在一个列表中的一些其他的对象。

另一种办法将是:

Versionized化和转换之前,反
serialize你的对象国作为上面提到的(与一个版本属性)。
当反序列化看版本属性,如果这不是你期望转化对象国与xsl-脚本或c#码给你的前版本。你可以保存一个清单xsl转换在当前项目

- conversions
    - v1-v2
    - v2-v3

如果你是目前在第3版和想载你xml文件的看版本属性和运行的所有xsl脚本以获得当前版本(第3版).所以你会跑xsl-脚本v1-v2和之后v2-3.

在这种情况下你可以拥有正常化,并反课程,必须不关心倒退的能力。

它是相当微不足道的使用 数据结合配合对象模型 UI。

我怎么能配合对象GUI控制没有一个持久性存储?如果我做手工,这意味着我必须写荒谬量的代码,用于每一个个单一的对象中存储器。我已经有某些种类的储存对于这种数据,但它不是结合进行排序的情况,它就像读这写在这里。

我应该写入一个装载机,它载列化的XML和获取的对象,然后阅读对象并填写了整个GUI?显然,这更像手册载入不具约束力。我失去了一些东西?

这里是一大篇关于如何使你的一类或结构的序列化。我会创造一级,这将允许你在商店的所有数据。使类serialable.这种方式在只有几行的代码你可以保存所有你的数据文件。然后只用一些更多线的代码你可以检索的数据文件。

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

一种替代将你的课程是使用一个ADO.NET 数据集的数据存储,这有内在的设施持续存在XML文件。代码将是最小的,你可以仅储存有关数据需要通过设计的表格,适合的模型的操作你的执行情况。此外,还将能够使用相同的代码如果你决定之后持续存在的UI国家一个数据库,而不是一个本地的文件。你只需要有一个备用功能来保存的数据集。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top