WPF中使用Caliburn.Micro MVVM写入关联RepairOrder与WriteOff数据到文件的最优方案
嘿,针对你用Caliburn.Micro开发WPF时遇到的持久化问题,我整理了几个实用方案,帮你把所有RepairOrder及其关联的WriteOff数据顺利写入文件:
方案一:JSON序列化(最推荐,简单灵活)
JSON是目前最常用的序列化格式,处理嵌套对象非常方便,而且Caliburn.Micro的BindableCollection继承自ObservableCollection,序列化起来几乎不需要额外处理。
步骤:
- 安装序列化库:如果用Newtonsoft.Json(Json.NET),在NuGet包管理器里搜索安装
Newtonsoft.Json;如果用.NET Core/.NET 5+自带的System.Text.Json,不需要额外安装。 - 编写序列化/反序列化代码:在你的ViewModel里添加保存和读取方法,直接操作
RepairOrders集合即可——因为每个RepairOrder已经包含了关联的BindableCollection<WriteOff>,序列化会自动递归处理所有嵌套的WriteOff数据。
示例代码(Newtonsoft.Json版本):
using Newtonsoft.Json; using System.IO; using Caliburn.Micro; // 假设你的ViewModel中有这个核心集合 public BindableCollection<RepairOrder> RepairOrders { get; set; } = new BindableCollection<RepairOrder>(); // 保存数据到JSON文件 public void SaveRepairData(string filePath) { try { // 把BindableCollection转成List(可选,直接序列化BindableCollection也可行) var repairOrdersList = RepairOrders.ToList(); // 序列化,Formatting.Indented让JSON更易读 string jsonContent = JsonConvert.SerializeObject(repairOrdersList, Formatting.Indented); // 写入文件 File.WriteAllText(filePath, jsonContent); } catch (IOException ex) { // 这里可以添加错误提示,比如用Caliburn.Micro的IWindowManager弹出提示 Console.WriteLine($"保存失败:{ex.Message}"); } } // 从JSON文件加载数据 public void LoadRepairData(string filePath) { try { string jsonContent = File.ReadAllText(filePath); var repairOrdersList = JsonConvert.DeserializeObject<List<RepairOrder>>(jsonContent); // 把List转回BindableCollection,保持Caliburn.Micro的通知特性 RepairOrders = new BindableCollection<RepairOrder>(repairOrdersList); // 如果需要通知UI更新,可以调用NotifyOfPropertyChange(() => RepairOrders); } catch (IOException ex) { Console.WriteLine($"加载失败:{ex.Message}"); } }
注意点:
- 如果你的
RepairOrder或WriteOff类里有不可序列化的属性(比如ICommand、UI控件引用),要给这些属性标记[JsonIgnore],避免序列化报错。 - 反向引用问题?不用担心,你提到WriteOff没有指向RepairOrder的引用,所以不会出现循环序列化的问题。
方案二:XML序列化(适合需要结构化XML的场景)
如果你的项目要求用XML格式存储数据,XML序列化也是个不错的选择,同样能自动处理嵌套的WriteOff集合。
示例代码:
using System.Xml.Serialization; using System.IO; using Caliburn.Micro; public void SaveToXml(string filePath) { try { var serializer = new XmlSerializer(typeof(List<RepairOrder>)); using (var writer = new StreamWriter(filePath)) { serializer.Serialize(writer, RepairOrders.ToList()); } } catch (IOException ex) { Console.WriteLine($"保存XML失败:{ex.Message}"); } } public void LoadFromXml(string filePath) { try { var serializer = new XmlSerializer(typeof(List<RepairOrder>)); using (var reader = new StreamReader(filePath)) { var repairOrdersList = (List<RepairOrder>)serializer.Deserialize(reader); RepairOrders = new BindableCollection<RepairOrder>(repairOrdersList); } } catch (IOException ex) { Console.WriteLine($"加载XML失败:{ex.Message}"); } }
注意点:
- 确保
RepairOrder和WriteOff类的公共属性都有get和set访问器,XML序列化需要读取和写入这些属性。 - 如果有自定义复杂类型属性,可能需要用
[XmlInclude]标记,告诉序列化器包含这些类型。
方案三:自定义CSV格式(适合极简数据场景)
如果你的数据结构非常简单,也可以用CSV存储,但因为存在嵌套的WriteOff集合,需要拆分存储:
- 一个CSV文件存所有RepairOrder的基础信息(包含唯一ID)
- 另一个CSV文件存所有WriteOff的信息,每条记录关联对应的RepairOrder ID
示例思路(伪代码):
// 保存RepairOrder到CSV using (var writer = new StreamWriter("RepairOrders.csv")) { writer.WriteLine("Id,OrderNumber,CustomerName"); // 表头 foreach (var order in RepairOrders) { writer.WriteLine($"{order.Id},{order.OrderNumber},{order.CustomerName}"); } } // 保存WriteOff到CSV using (var writer = new StreamWriter("WriteOffs.csv")) { writer.WriteLine("Id,RepairOrderId,Amount,Reason"); // 表头 foreach (var order in RepairOrders) { foreach (var writeOff in order.WriteOffs) { writer.WriteLine($"{writeOff.Id},{order.Id},{writeOff.Amount},{writeOff.Reason}"); } } }
这种方式需要自己处理CSV的读写和数据关联,适合数据量小、结构简单的场景,不如序列化方案省心。
内容的提问来源于stack exchange,提问作者Dwayne B
相关产品推荐
相关产品推荐

