diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/XmlParser/RawObjects.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/XmlParser/RawObjects.cs
index 6d4337824b..28a4fdfee2 100644
--- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/XmlParser/RawObjects.cs
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/XmlParser/RawObjects.cs
@@ -39,17 +39,17 @@ namespace ICSharpCode.AvalonEdit.XmlParser
public RawObject Parent { get; set; }
-// public RawDocument Document {
-// get {
-// if (this.Parent != null) {
-// return this.Parent.Document;
-// } else if (this is RawDocument) {
-// return (RawDocument)this;
-// } else {
-// return null;
-// }
-// }
-// }
+ public RawDocument Document {
+ get {
+ if (this.Parent != null) {
+ return this.Parent.Document;
+ } else if (this is RawDocument) {
+ return (RawDocument)this;
+ } else {
+ return null;
+ }
+ }
+ }
/// Occurs when the value of any local properties changes. Nested changes do not cause the event to occur
public event EventHandler LocalDataChanged;
@@ -76,6 +76,11 @@ namespace ICSharpCode.AvalonEdit.XmlParser
this.ReadCallID = new object();
}
+ public virtual IEnumerable GetSelfAndAllChildren()
+ {
+ return new RawObject[] { this };
+ }
+
public virtual void UpdateDataFrom(RawObject source)
{
this.ReadCallID = source.ReadCallID;
@@ -139,6 +144,14 @@ namespace ICSharpCode.AvalonEdit.XmlParser
UpdateChildrenFrom(src.Children);
}
+ public override IEnumerable GetSelfAndAllChildren()
+ {
+ return Enumerable.Union(
+ new RawContainer[] { this },
+ this.Children.SelectMany(x => x.GetSelfAndAllChildren())
+ );
+ }
+
// The following should be the only methods that are ever
// used to modify the children collection
@@ -153,23 +166,24 @@ namespace ICSharpCode.AvalonEdit.XmlParser
LogDom("Inserting {0} at index {1}", item, index);
item.Parent = this;
this.Children.Insert(index, item);
-// if (this.Document != null) {
-// foreach(RawObject obj in GetSeftAndAllNestedObjects()) {
-// this.Document.OnObjectAttached(new RawObjectEventArgs() { Object = obj });
-// }
-// }
+ if (this.Document != null) {
+ foreach(RawObject obj in GetSelfAndAllChildren()) {
+ this.Document.OnObjectAttached(item);
+ }
+ }
}
protected virtual void RemoveAt(int index)
{
- LogDom("Removing {0} at index {1}", this.Children[index], index);
- this.Children[index].Parent = null;
+ RawObject removedItem = this.Children[index];
+ LogDom("Removing {0} at index {1}", removedItem, index);
+ removedItem.Parent = null;
this.Children.RemoveAt(index);
-// if (this.Document != null) {
-// foreach(RawObject obj in GetSeftAndAllNestedObjects()) {
-// this.Document.OnObjectDettached(new RawObjectEventArgs() { Object = obj });
-// }
-// }
+ if (this.Document != null) {
+ foreach(RawObject obj in GetSelfAndAllChildren()) {
+ this.Document.OnObjectDettached(removedItem);
+ }
+ }
}
///
@@ -255,37 +269,43 @@ namespace ICSharpCode.AvalonEdit.XmlParser
public class RawDocument: RawContainer
{
-// public event EventHandler ObjectAttached;
-// public event EventHandler ObjectDettached;
+ public event EventHandler ObjectAttached;
+ public event EventHandler ObjectDettached;
+
+ internal void OnObjectAttached(RawObject obj)
+ {
+ if (ObjectAttached != null) ObjectAttached(this, new RawObjectEventArgs() { Object = obj } );
+ }
+
+ internal void OnObjectDettached(RawObject obj)
+ {
+ if (ObjectDettached != null) ObjectDettached(this, new RawObjectEventArgs() { Object = obj } );
+ }
-// internal void OnObjectAttached(RawObjectEventArgs e)
-// {
-// if (ObjectAttached != null) ObjectAttached(this, e);
-// }
-//
-// internal void OnObjectDettached(RawObjectEventArgs e)
-// {
-// if (ObjectDettached != null) ObjectDettached(this, e);
-// }
+ XDocument xDoc;
- public XDocument CreateXDocument(bool autoUpdate)
+ public XDocument GetXDocument()
{
- LogLinq("Creating XDocument");
- XDocument doc = new XDocument();
- doc.AddAnnotation(this);
- UpdateXDocument(doc, autoUpdate);
- this.Children.CollectionChanged += delegate { UpdateXDocument(doc, autoUpdate); };
- return doc;
+ if (xDoc == null) {
+ LogLinq("Creating XDocument");
+ xDoc = new XDocument();
+ xDoc.AddAnnotation(this);
+ UpdateXDocumentChildren(true);
+ this.Children.CollectionChanged += delegate { UpdateXDocumentChildren(false); };
+ }
+ return xDoc;
}
- void UpdateXDocument(XDocument doc, bool autoUpdate)
+ void UpdateXDocumentChildren(bool firstUpdate)
{
+ if (!firstUpdate) LogLinq("Updating XDocument Children");
+
RawElement root = this.Children.OfType().FirstOrDefault(x => x.StartTag.OpeningBracket == "<");
- if (doc.Root.GetRawObject() != root) {
+ if (xDoc.Root.GetRawObject() != root) {
if (root != null) {
- doc.ReplaceNodes(root.CreateXElement(autoUpdate));
+ xDoc.ReplaceNodes(root.GetXElement());
} else {
- doc.RemoveNodes();
+ xDoc.RemoveNodes();
}
}
}
@@ -344,46 +364,48 @@ namespace ICSharpCode.AvalonEdit.XmlParser
}
}
- public XElement CreateXElement(bool autoUpdate)
+ XElement xElem;
+
+ public XElement GetXElement()
{
- LogLinq("Creating XElement '{0}'", this.StartTag.Name);
- XElement elem = new XElement(EncodeXName(this.StartTag.Name, this.StartTag.Namesapce));
- elem.AddAnnotation(this);
- UpdateXElement(elem, autoUpdate);
- UpdateXElementAttributes(elem, autoUpdate);
- UpdateXElementChildren(elem, autoUpdate);
- if (autoUpdate) {
- this.StartTag.LocalDataChanged += delegate { UpdateXElement(elem, autoUpdate); };
- this.StartTag.Children.CollectionChanged += delegate { UpdateXElementAttributes(elem, autoUpdate); };
- this.Children.CollectionChanged += delegate { UpdateXElementChildren(elem, autoUpdate); };
+ if (xElem == null) {
+ LogLinq("Creating XElement '{0}'", this.StartTag.Name);
+ xElem = new XElement(EncodeXName(this.StartTag.Name, this.StartTag.Namesapce));
+ xElem.AddAnnotation(this);
+ UpdateXElement(true);
+ UpdateXElementAttributes(true);
+ UpdateXElementChildren(true);
+ this.StartTag.LocalDataChanged += delegate { UpdateXElement(false); };
+ this.StartTag.Children.CollectionChanged += delegate { UpdateXElementAttributes(false); };
+ this.Children.CollectionChanged += delegate { UpdateXElementChildren(false); };
}
- return elem;
+ return xElem;
}
- void UpdateXElement(XElement elem, bool autoUpdate)
+ void UpdateXElement(bool firstUpdate)
{
- LogLinq("Updating XElement '{0}'", this.StartTag.Name);
- elem.Name = EncodeXName(this.StartTag.Name, this.StartTag.Namesapce);
+ if (!firstUpdate) LogLinq("Updating XElement '{0}'", this.StartTag.Name);
+
+ xElem.Name = EncodeXName(this.StartTag.Name, this.StartTag.Namesapce);
}
- internal void UpdateXElementAttributes(XElement elem, bool autoUpdate)
+ internal void UpdateXElementAttributes(bool firstUpdate)
{
- List xAttrs = new List();
- foreach(RawAttribute attr in this.StartTag.Children.OfType()) {
- XAttribute existing = elem.Attributes().FirstOrDefault(x => x.GetRawObject() == attr);
- xAttrs.Add(existing ?? attr.CreateXAttribute(autoUpdate));
- }
- elem.ReplaceAttributes(xAttrs.ToArray());
+ if (!firstUpdate) LogLinq("Updating XElement Attributes of '{0}'", this.StartTag.Name);
+
+ xElem.ReplaceAttributes(); // Otherwise we get duplicate item exception
+ xElem.ReplaceAttributes(
+ this.StartTag.Children.OfType().Select(x => x.GetXAttribute()).ToArray()
+ );
}
- void UpdateXElementChildren(XElement elem, bool autoUpdate)
+ void UpdateXElementChildren(bool firstUpdate)
{
- List xElems = new List();
- foreach(RawElement rawElem in this.Children.OfType()) {
- XElement existing = (XElement)elem.Nodes().FirstOrDefault(x => x.GetRawObject() == rawElem);
- xElems.Add(existing ?? rawElem.CreateXElement(autoUpdate));
- }
- elem.ReplaceNodes(xElems);
+ if (!firstUpdate) LogLinq("Updating XElement Children of '{0}'", this.StartTag.Name);
+
+ xElem.ReplaceNodes(
+ this.Children.OfType().Select(x => x.GetXElement()).ToArray()
+ );
}
public override string ToString()
@@ -417,28 +439,32 @@ namespace ICSharpCode.AvalonEdit.XmlParser
}
}
- public XAttribute CreateXAttribute(bool autoUpdate)
+ XAttribute xAttr;
+
+ public XAttribute GetXAttribute()
{
- LogLinq("Creating XAttribute '{0}={1}'", this.Name, this.Value);
- XAttribute attr = new XAttribute(EncodeXName(this.Name, this.Namesapce), string.Empty);
- attr.AddAnnotation(this);
- bool deleted = false;
- UpdateXAttribute(attr, autoUpdate, ref deleted);
- if (autoUpdate) this.LocalDataChanged += delegate { UpdateXAttribute(attr, autoUpdate, ref deleted); };
- return attr;
+ if (xAttr == null) {
+ LogLinq("Creating XAttribute '{0}={1}'", this.Name, this.Value);
+ xAttr = new XAttribute(EncodeXName(this.Name, this.Namesapce), string.Empty);
+ xAttr.AddAnnotation(this);
+ bool deleted = false;
+ UpdateXAttribute(true, ref deleted);
+ this.LocalDataChanged += delegate { if (!deleted) UpdateXAttribute(false, ref deleted); };
+ }
+ return xAttr;
}
- void UpdateXAttribute(XAttribute attr, bool autoUpdate, ref bool deleted)
+ void UpdateXAttribute(bool firstUpdate, ref bool deleted)
{
- if (deleted) return;
- LogLinq("Updating XAttribute '{0}={1}'", this.Name, this.Value);
- if (attr.Name == EncodeXName(this.Name, this.Namesapce)) {
- attr.Value = this.Value ?? string.Empty;
+ if (!firstUpdate) LogLinq("Updating XAttribute '{0}={1}'", this.Name, this.Value);
+
+ if (xAttr.Name == EncodeXName(this.Name, this.Namesapce)) {
+ xAttr.Value = this.Value ?? string.Empty;
} else {
- XElement parent = attr.Parent;
- attr.Remove();
- deleted = true;
- ((RawElement)parent.GetRawObject()).UpdateXElementAttributes(parent, autoUpdate);
+ xAttr.Remove();
+ xAttr = null;
+ deleted = true; // No longer get events for this instance
+ ((RawElement)this.Parent.Parent).UpdateXElementAttributes(false);
}
}
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/XmlParser/XmlParser.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/XmlParser/XmlParser.cs
index 496cafe78b..4e604a26f1 100644
--- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/XmlParser/XmlParser.cs
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/XmlParser/XmlParser.cs
@@ -28,7 +28,7 @@ namespace ICSharpCode.AvalonEdit.XmlParser
public XmlParser(TextDocument textDocument)
{
- this.userLinqDocument = userDocument.CreateXDocument(true);
+ this.userLinqDocument = userDocument.GetXDocument();
this.textDocument = textDocument;
this.textDocument.Changed += delegate(object sender, DocumentChangeEventArgs e) {
changesSinceLastParse.Add(e);
@@ -50,12 +50,15 @@ namespace ICSharpCode.AvalonEdit.XmlParser
end = Math.Max(Math.Min(end, textDocument.TextLength - 1), 0);
foreach(RawObject obj in parsedItems.FindOverlappingSegments(start, end - start)) {
parsedItems.Remove(obj);
- Log("Removed cached item: {0}", obj);
+ Log("Removed cached item {0}", obj);
}
}
changesSinceLastParse.Clear();
RawDocument parsedDocument = ReadDocument();
+ if (parsedDocument.ReadCallID != userDocument.ReadCallID) {
+ RawObject.LogDom("Updating main DOM tree...");
+ }
userDocument.UpdateDataFrom(parsedDocument);
return userDocument;
}