目錄
- 序列化
- 保存
- 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
(包括JObject
和JArray
)由于其設計為可以包含自身類型的實例(例如,一個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);
}