Netron是一個C#開源圖形庫,可以幫助開發人員開發出類似Visio的作圖軟件。本文繼前文”Netron開發快速上手(一)“討論如何利用Netron里的序列化功能快速保存自己開發的圖形對象。
一個用Netron開發的實際應用請看:發布一個免費開源軟件-- PAD流程圖繪制軟件PADFlowChart
一、 Netron對象序列化
序列化Netron對象需要以下幾個步驟:
- 添加序列化標簽]Serializable]
[Serializable] public class BlockShape : AbstractFlowChartShape
- 實現ISerializable接口
如果是從Shape類或Entity類(Shape類的父類)繼承,則已經繼承了ISerializable接口,你需要做的就是重載GetObjectData方法,該方法用於序列化時被序列化過程調用,提供要序列化的數據
public override void GetObjectData(SerializationInfo info, StreamingContext context) { base.GetObjectData(info, context); info.AddValue("m_leftConnector", m_leftConnector); … }
GetObjectData方法要先調用基類的方法,否則基類的數據不會被序列化。
用info.AddValue()加入你要序列化的數據
- 實現序列化的構造函數
類的序列化構造函數用於反序列化對象。當從磁盤讀取序列化數據時,用於生成相應的對象。下面是個例子:
protected BlockShape(SerializationInfo info, StreamingContext context) : base(info, context) { m_leftConnector = (Connector)info.GetValue("m_leftConnector", typeof(Connector)); m_leftConnector.BelongsTo = this; Connectors.Add(m_leftConnector); … }
a) 注意要調用基類的序列化構造函數。
b) 用info.GetValue(“<數據名字>”,<數據類型>)來反序列化數據
- 必要時重載IEntity:PostDeserialization()方法
IEntity::PostDeserialization()方法將會在Netron的反序列化過程中被Netron.GraphLib.IO.Binary.BinarySerializer::UnwrapBundle()方法調用,調用的時機是所有對象建立以后。在這里你可以做一些初始化工作。因為反序列化時除了序列化構造函數其它的構造函數是不會被調用的。
二、 添加“打開/保存”代碼
添加了圖形對象的序列化代碼后,你還需要在自己的應用程序中對“打開/保存”菜單命令添加相應的代碼來打開/保存你的數據
- 打開文件:
GraphControl::Open()
- 保存文件:
GraphControl::SaveAs()
另外你可以用GraphControl::IsDirty來判斷目前畫布上的圖形對象是否已經發生了改變需要保存;
GraphControl::OnDirtyChanged事件可以在畫布上的內容發生改變后通知開發人員做相應的處理。
三、 Netron序列化過程分析
- Netron的序列化過程如下:
GraphControl:: SaveAs()
=>IO.Binary.BinarySerializer::SaveAs()
=> BinaryCapsule:: GetObjectData()
=>GraphAbstract:: GetObjectData()
而在GraphAbstract:: GetObjectData()里則分別序列化了其中的Shapes和Connections,對集合Shapes和Connections的序列化會導致Shape及Connection的GetObjectData()方法被調用。
- Netron的反序列化過程如下:
GraphControl:: Open
=> IO.Binary.BinarySerializer:: Open()
=> BinaryFormatter:: Deserialize()
BinaryFormatter:: Deserialize()將會在讀取序列化文件時調用相應對象的序列化構造函數進行反序列化。和前述序列化過程相反,反序列化過程會先調用Shape和Connection的序列化構造函數生成Shapes和Connections集合,然后調用GraphAbstract的序列化構造函數生成GrapAbstract對象,然后生成BinaryCapsule對象。
隨后IO.Binary.BinarySerializer:: Open()將調用UnwrapBundle()方法,使Connection和Shape的Connector連接起來。因為在Netron中,Shape通過Connection相連,而Connection的From/To都指向Shape的Connector成員,在序列化過程中,Connector對象是在Shape中進行序列化,而Connection則只序列化了From/To的UID(String類型); UnwrapBundle()方法將對每一個Connection對象查找和From UID/To UID匹配的Connector,然后將Connection的From/To指向相應的Connector對象。
最后,在UnwrapBundle()方法中還會調用Shape和Connection的PostDeserialization()。