Click here to Skip to main content
15,891,841 members
Articles / Programming Languages / XML

A Custom .NET XML Serialization Library

Rate me:
Please Sign up or sign in to vote.
4.43/5 (4 votes)
25 Jan 200611 min read 42.3K   432   21  
Describes a custom XML serialization library, with functionality to compare for, and to combine differences
using System;
using System.Collections;
using System.IO;

using Wxv.Wml;
using Wxv.Wml.IO;
using Wxv.Wml.Serialization;

namespace Wxv.WmlDemo
{
	public delegate void DataDocumentModified ();

	public class DataObjectDifferences
	{
		private string modifyCommandName;
		public string ModifyCommandName { get { return modifyCommandName; } }

		private bool dirtyBefore;
		public bool DirtyBefore { get { return dirtyBefore; } }

		private WmlDocument redoDifferences;
		public WmlDocument RedoDifferences { get { return redoDifferences; } } 

		private WmlDocument undoDifferences;
		public WmlDocument UndoDifferences { get { return undoDifferences; } } 

		public DataObjectDifferences (string modifyCommandName, bool dirtyBefore, WmlDocument redoDifferences, WmlDocument undoDifferences)
		{
			this.modifyCommandName = modifyCommandName;
			this.dirtyBefore = dirtyBefore;
			this.redoDifferences = redoDifferences;
			this.undoDifferences = undoDifferences;
		}
	}
	
	public class DataDocument
	{
		public const int MaxDifferencesCount = 20;

		private WmlDocument previousDataObject;

		private DataObject dataObject = new DataObject();
		public DataObject DataObject
		{
			get { return dataObject; }
		}

		private bool dirty;
		public bool Dirty { get { return dirty; } }

		private ArrayList differences = new ArrayList();
		private int differencesIndex = 0;

		private string modifyCommandName;
		private int modifyCount;

		public event DataDocumentModified OnModified;

		public DataDocument()
		{
			previousDataObject = WmlSerializer.Serialize (dataObject);
		}

		public void BeginModifyCommand (string modifyCommandName)
		{
			if (modifyCount == 0)
				this.modifyCommandName = modifyCommandName;
			modifyCount++;
		}

		public void EndModifyCommand()
		{
			if (modifyCount == 0)
				throw new Exception ("Mismatched call to EndModify");

			modifyCount--;
			if (modifyCount != 0) 
				return;

			if (!BuildDifferences())
				return; // no modifications made

			dirty = true;
			RaiseOnModified ();
		}

		private bool BuildDifferences()
		{
			WmlDocument redoDifferences = WmlSerializer.Compare (previousDataObject, dataObject, false);
			
			// no differences
			if (redoDifferences.Count == 0)
				return false;

			WmlDocument undoDifferences = WmlSerializer.Compare (dataObject, previousDataObject, false);

			// remove the undo/redo steps ahead of the current index
			while (differencesIndex < differences.Count)
				differences.RemoveAt (differencesIndex);
			
			// add the differences to the list
			differences.Add (new DataObjectDifferences (modifyCommandName, dirty, redoDifferences, undoDifferences));
			if (differences.Count > MaxDifferencesCount)
				differences.RemoveAt (0);
			else
				differencesIndex++;

			// update the previous data object
			WmlSerializer.Combine (redoDifferences, previousDataObject, false);

			return true;
		}

		private void RaiseOnModified ()
		{
			if (OnModified != null)
				OnModified ();		
		}

		public bool CanUndo
		{
			get { return ((differencesIndex - 1) >= 0) && ((differencesIndex - 1) < differences.Count); }
		}

		public DataObjectDifferences CurrentUndoDifference
		{
			get
			{
				if (CanUndo)
					return (DataObjectDifferences) differences [differencesIndex - 1];
				else
					return null;
			}
		}

		public void Undo()
		{
			if (!CanUndo)
				return;

			DataObjectDifferences differences = CurrentUndoDifference;

			dirty = differences.DirtyBefore;

			// roll back the data object
			WmlSerializer.Combine (differences.UndoDifferences, dataObject, false);

			// roll back the previous data object (which is still the same as the data object)
			WmlSerializer.Combine (differences.UndoDifferences, previousDataObject, false);
            
			differencesIndex--;
			RaiseOnModified ();
		}

		public bool CanRedo
		{
			get { return (differencesIndex >= 0) && (differencesIndex < differences.Count); }
		}

		public DataObjectDifferences CurrentRedoDifference
		{
			get
			{
				if (CanRedo)
					return (DataObjectDifferences) differences [differencesIndex];
				else
					return null;
			}
		}

		public void Redo()
		{
			if (!CanRedo)
				return;

			DataObjectDifferences differences = CurrentRedoDifference;

			dirty = true; // rolling forward always makes it dirty, because a save resets the undo/redo differences

			// roll forward the data object
			WmlSerializer.Combine (differences.RedoDifferences, dataObject, false);

			// roll forward the previous data object (which is still the same as the data object)
			WmlSerializer.Combine (differences.RedoDifferences, previousDataObject, false);
            
			differencesIndex++;
			RaiseOnModified ();
		}


	}

}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.


Written By
Web Developer
New Zealand New Zealand
Im a Software Developer working in Auckland, New Zealand. When i was a lot shorter, i started programming in Atari Basic, though these days its mostly C#, and a bit of java (mostly the caffinated kind).

Comments and Discussions