当前位置: 首页 > news >正文

【Syncfusion系列】Diagram 杂谈 第三篇 序列化和反序列化

目录

  • 序列化
    • 保存
      • C# 代码示例, 方式1 :
      • C# 代码示例, 方式2 :
  • 反序列化
    • 加载
      • C# 代码示例, 方式1:
      • C# 代码示例, 方式2:
    • **如何序列化自定义属性**
    • 序列化和反序列化都存在的一个问题
      • 解决方式
  • 图表是否已修改?
  • 如何在新版本中加载SfDiagram的旧版本

序列化

序列化是将SfDiagram对象的状态转换为字节流的过程,以便在需要时重新创建它们。这样的流可以存储在数据库中、作为文件或内存中。相反的过程称为反序列化。

保存

在SfDiagram中,使用DataContractSerializer进行序列化。DataContractSerializer的功能适用于SfDiagram序列化。它支持将SfDiagram保存到流中。SfDiagram会连同其所有属性一起被保存。

C# 代码示例, 方式1 :

// 将文件保存为流
SaveFileDialog dialog = new SaveFileDialog();
dialog.Title = "保存XAML";
dialog.Filter = "XAML文件(*.xaml)|*.xaml";
if (dialog.ShowDialog() == true)
{using (Stream str = File.Open(dialog.FileName, FileMode.CreateNew)){sfDiagram.Save(str);}
}

C# 代码示例, 方式2 :

  // 将保存为内存流(FileMode.Create 会覆盖已有的,FileMode.CreateNew 不会覆盖已有的)using (Stream str = File.Open(GlobalData.Instance.WfFullName, FileMode.Create)){diagram.Save(str);}

反序列化

加载

在反序列化过程中,使用保存的流来加载当前视图中的SfDiagram节点和连接器。通过这种方式,你可以通过加载适当的流继续处理之前保存的SfDiagram。

C# 代码示例, 方式1:

// 从保存的XAML文件中加载
OpenFileDialog dialog = new OpenFileDialog();
if (dialog.ShowDialog() == true)
{using (Stream myStream = dialog.OpenFile()){sfDiagram.Load(myStream);}
}

C# 代码示例, 方式2:

// 从保存的内存流中加载
using (FileStream fileStream = new FileStream(FullName, FileMode.Open, FileAccess.Read))
{diagram.Load(fileStream);
}

如何序列化自定义属性

在SfDiagram中,你不能序列化每个图表对象的Content和ContentTemplate。如果你想保留图表对象的ContentTemplate,请将它们保存在资源中,并在图表对象添加到图表页面后应用它们。

自定义类中的自定义属性,如果从SfDiagram的任何接口或任何视图模型类派生,则可以通过DataMember属性进行序列化。

C# 代码示例:

public class NodeContent : INode
{[DataMember]public string NodeType{get;set;}
}

也就是说,只要你添加了[DataMember]特性,你自己添加的属性也会被序列化!
但前提是,你的这个类是从SfDiagram的接口或任何视图模型类派生的

注意

SfDiagram的接口和视图模型类是在没有DataContract属性的情况下创建的。因此,对于从这些类派生的类,你不需要添加DataContract属性。

如何序列化自定义类

您可以借助 DataContract 属性和 SfDiagram 的 KnownTypes 属性来序列化业务类。您必须添加 DataContract 属性来序列化整个类。

(再说一次人话): 在进行序列化操作时,如果你有一个业务类(business class),并且这个类没有从任何已经标记了DataContract属性的基类(base class)继承,那么你需要给这个类添加DataContract属性来序列化整个类。简而言之,如果一个类没有继承自一个已经定义了DataContract属性的基类,那么你需要为这个类本身添加DataContract属性,以便能够对其进行序列化。

C# 代码示例:

[DataContract]
public class NodeContent
{[DataMember]public string NodeType{get;set;}
}Diagram.KnownTypes = () => new List<Type>()
{typeof(NodeContent)
};

序列化和反序列化都存在的一个问题

我自己定义一个继承自SfDiagram的接口和视图模型类的类

public class VisualNode : BpmnNodeViewModel
{[DataMember]public string? IDString { get; set; } = null;/// <summary>/// 为view窗口名称,用于打开对于节点窗口!/// </summary>[DataMember]public string NodeViewType { get; set; } = "Activity";/// <summary>/// 工作流节点类型/// </summary>[DataMember]public string StepType { get; set; } = "";/// <summary>/// 记录输入参数(为了方便Diagram自带的序列化可以进行,这里需要改为string类型)/// </summary>[DataMember]public JObject Inputs { get; set; } = null;/// <summary>/// 记录输出参数(为了方便Diagram自带的序列化可以进行,这里需要改为string类型)/// </summary>[DataMember]public JObject Outputs { get; set; } = null;
}

在C#中使用序列化时,如果遇到System.Runtime.Serialization.InvalidDataContractException错误,特别是涉及到Newtonsoft.Json.Linq.JToken类型时,通常是因为JToken类型是一个递归集合数据,这在序列化过程中不被支持。错误信息提示:“Type ‘Newtonsoft.Json.Linq.JToken’ is a recursive collection data contract which is not supported. Consider modifying the definition of collection ‘Newtonsoft.Json.Linq.JToken’ to remove references to itself.”。

JToken(包括JObjectJArray)由于其设计为可以包含自身类型的实例(例如,一个JObject可以包含另一个JObject作为其属性值),导致了递归定义,这在数据契约序列化中是不被允许的。

解决方式

将他们改成string 格式!

   /// </summary>[DataMember]public string Inputs { get; set; } = "{}";/// <summary>/// 记录输出参数(为了方便Diagram自带的序列化可以进行,这里需要改为string类型)/// </summary>[DataMember]public string Outputs { get; set; } = "{}";

JObject 存的时候先序列化

node.Outputs = JsonConvert.SerializeObject(obj);

JObject 用的时候,再反序列化即可

jsonStepData.Outputs = JsonConvert.DeserializeObject<JObject>(FirstFuncNode.Outputs);

图表是否已修改?

图表控件的HasChanges属性用于通知图表是否有未保存的更改。该属性跟踪通过交互和公共API所做的所有更改。

XAML 代码示例:

<!-- 初始化图表 -->
<Syncfusion:SfDiagram x:Name="diagram">
</Syncfusion:SfDiagram>
<!-- 初始化保存图表的按钮 -->
<Button x:Name="SaveButton" Content="保存" Click="SaveButton_Click">
</Button>
//Method to promote the save dialouge box when diagram has any unsaved changes.
private void SaveButton_Click(object sender, RoutedEventArgs e)
{if (diagram != null && diagram.HasChanges){MessageBoxResult messageBoxResult = MessageBox.Show("Do you want to save the Diagram?","SfDiagram",MessageBoxButton.YesNo);if (messageBoxResult == MessageBoxResult.Yes){SaveDiagram();}}
}//Method to save the diagram.
private void SaveDiagram()
{SaveFileDialog dialog = new SaveFileDialog();dialog.Title = "Save XAML";dialog.Filter = "XAML File (*.xaml)|*.xaml";if (dialog.ShowDialog() == true){File.Delete(dialog.FileName);using (Stream s = File.Open(dialog.FileName, FileMode.OpenOrCreate)){diagram.Save(s);}}
}

如何在新版本中加载SfDiagram的旧版本

你可以通过升级方法在新版本中加载任何旧版本的SfDiagram流。请参考以下代码示例。

C# 代码示例:

using (Stream myStream = dialog.OpenFile())
{sfDiagram.Upgrade(myStream);sfDiagram.Load(myStream);
}
http://www.lryc.cn/news/504524.html

相关文章:

  • Apache APISIX快速入门
  • 【经典】制造供应链四类策略(MTS、MTO、ATO、ETO)细说
  • 基于stm32的红外测温系统设计(论文+源码)
  • 前端WebSocket应用——聊天实时通信的基本配置
  • 博弈论1:拿走游戏(take-away game)
  • Debezium OracleValueConverters 分析
  • WPF 消息循环(二)
  • ubuntu上更改ext4格式的硬盘为 windows的 NTFS 格式参考
  • Fastapi教程:使用 aioredis 连接池执行Redis 的高效异步操作
  • 配置mysqld(读取选项内容,基本配置),数据目录(配置的必要性,目录下的内容,具体文件介绍,修改配置)
  • docker 容器相互访问
  • 算法1(蓝桥杯18)-删除链表的倒数第 N 个节点
  • 【PyTorch】动态调整学习率 torch.optim.lr_scheduler.StepLR 调度器
  • AIGC drug design 人工智能生成式药物设计:基于 GPT 的 SMILES 生成与应用
  • Python面试常见问题及答案4
  • 开启第二阶段---蓝桥杯
  • npm内存溢出
  • 回归预测 | MATLAB实现CNN-BiGRU卷积神经网络结合双向门控循环单元多输入单输出回归预测
  • Android系统卡启动问题排查
  • STP(生成树协议)
  • 【前端面试】随机、结构赋值、博弈题
  • Volta——开箱即用的Node.js 版本管理工具
  • ubuntu 磁盘空间满,找不到占用文件的目录
  • 1. 机器学习基本知识(5)——练习题(参考答案)
  • spark-sql 备忘录
  • 基于softmax回归的多分类
  • bs4基本运用
  • MySQL 时区参数 time_zone 详解
  • Redis - 消息队列 Stream
  • Docker:国内加速源