diff --git a/Content/UniversalEditor.Content.PlatformIndependent/Editors/Markup/MarkupEditor.glade b/Content/UniversalEditor.Content.PlatformIndependent/Editors/Markup/MarkupEditor.glade
new file mode 100644
index 00000000..85ce9d8d
--- /dev/null
+++ b/Content/UniversalEditor.Content.PlatformIndependent/Editors/Markup/MarkupEditor.glade
@@ -0,0 +1,308 @@
+
+
+
+
+
+
+
diff --git a/Content/UniversalEditor.Content.PlatformIndependent/UniversalEditor.Content.PlatformIndependent.csproj b/Content/UniversalEditor.Content.PlatformIndependent/UniversalEditor.Content.PlatformIndependent.csproj
index 4bc2260c..8315fae1 100644
--- a/Content/UniversalEditor.Content.PlatformIndependent/UniversalEditor.Content.PlatformIndependent.csproj
+++ b/Content/UniversalEditor.Content.PlatformIndependent/UniversalEditor.Content.PlatformIndependent.csproj
@@ -743,6 +743,7 @@
+
diff --git a/Libraries/UniversalEditor.UserInterface/Editors/Markup/MarkupEditor.cs b/Libraries/UniversalEditor.UserInterface/Editors/Markup/MarkupEditor.cs
new file mode 100644
index 00000000..aaa3343b
--- /dev/null
+++ b/Libraries/UniversalEditor.UserInterface/Editors/Markup/MarkupEditor.cs
@@ -0,0 +1,211 @@
+//
+// MarkupEditor.cs
+//
+// Author:
+// Michael Becker
+//
+// Copyright (c) 2020 Mike Becker's Software
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+using System;
+using System.Text;
+using MBS.Framework.UserInterface;
+using MBS.Framework.UserInterface.Controls;
+
+using UniversalEditor.ObjectModels.Markup;
+using UniversalEditor.UserInterface;
+
+namespace UniversalEditor.Editors.Markup
+{
+ [ContainerLayout("~/Editors/Markup/MarkupEditor.glade")]
+ public class MarkupEditor : Editor
+ {
+ private ListView tv;
+ private DefaultTreeModel tm;
+ private TextBox txtValue;
+ private SplitContainer scAttributesValue;
+
+ private static EditorReference _er = null;
+ public override EditorReference MakeReference()
+ {
+ if (_er == null)
+ {
+ _er = base.MakeReference();
+ _er.SupportedObjectModels.Add(typeof(MarkupObjectModel));
+ }
+ return _er;
+ }
+
+ public override void UpdateSelections()
+ {
+ }
+
+ protected override EditorSelection CreateSelectionInternal(object content)
+ {
+ return null;
+ }
+
+ protected override void OnCreated(EventArgs e)
+ {
+ base.OnCreated(e);
+ OnObjectModelChanged(e);
+ }
+
+ protected override void OnObjectModelChanged(EventArgs e)
+ {
+ base.OnObjectModelChanged(e);
+ if (!IsCreated) return;
+
+ tm.Rows.Clear();
+
+ MarkupObjectModel mom = (ObjectModel as MarkupObjectModel);
+ if (mom == null) return;
+
+ for (int i = 0; i < mom.Elements.Count; i++)
+ {
+ RecursiveLoadDocumentExplorer(mom.Elements[i], null);
+ }
+ }
+
+ private const int MAX_PREVIEW_LENGTH = 24;
+
+ private void RecursiveLoadDocumentExplorer(MarkupElement el, EditorDocumentExplorerNode parent)
+ {
+ string title = el.Name;
+ if (el is MarkupPreprocessorElement)
+ {
+ title = String.Format("{0} {1}?>", el.Name, el.Value);
+ }
+ else if (el is MarkupCommentElement)
+ {
+ title = String.Format("", el.Value.Substring(0, Math.Min(el.Value.Length, MAX_PREVIEW_LENGTH)), (el.Value.Length > MAX_PREVIEW_LENGTH ? "..." : String.Empty));
+ }
+ else if (el is MarkupTagElement)
+ {
+ MarkupTagElement tag = (el as MarkupTagElement);
+ StringBuilder sb = new StringBuilder();
+ sb.Append('<');
+ sb.Append(el.Name);
+ if (tag.Attributes.Count > 0)
+ {
+ sb.Append(' ');
+ for (int i = 0; i < tag.Attributes.Count; i++)
+ {
+ sb.Append(tag.Attributes[i].Name);
+ sb.Append('=');
+ sb.Append('"');
+ sb.Append(tag.Attributes[i].Value);
+ sb.Append('"');
+ if (i < tag.Attributes.Count - 1)
+ {
+ sb.Append(' ');
+ }
+ }
+ }
+
+ if (String.IsNullOrEmpty(el.Value))
+ {
+ sb.Append(" />");
+ }
+ else
+ {
+ sb.Append(">...");
+ sb.Append(el.Name);
+ sb.Append('>');
+ }
+ title = sb.ToString();
+ }
+
+ EditorDocumentExplorerNode node = new EditorDocumentExplorerNode(title);
+ node.SetExtraData("el", el);
+
+ if (el is MarkupContainerElement)
+ {
+ MarkupContainerElement ct = (el as MarkupContainerElement);
+ for (int i = 0; i < ct.Elements.Count; i++)
+ {
+ RecursiveLoadDocumentExplorer(ct.Elements[i], node);
+ }
+ }
+
+ if (parent == null)
+ {
+ DocumentExplorer.Nodes.Add(node);
+ }
+ else
+ {
+ parent.Nodes.Add(node);
+ }
+ }
+
+ protected internal override void OnDocumentExplorerSelectionChanged(EditorDocumentExplorerSelectionChangedEventArgs e)
+ {
+ base.OnDocumentExplorerSelectionChanged(e);
+
+ tm.Rows.Clear();
+ if (e.Node != null)
+ {
+ MarkupElement el = e.Node.GetExtraData("el");
+ if (el is MarkupTagElement)
+ {
+ MarkupTagElement tag = (el as MarkupTagElement);
+ for (int i = 0; i < tag.Attributes.Count; i++)
+ {
+ TreeModelRow row = new TreeModelRow(new TreeModelRowColumn[]
+ {
+ new TreeModelRowColumn(tm.Columns[0], tag.Attributes[i].Name),
+ new TreeModelRowColumn(tm.Columns[1], tag.Attributes[i].Value)
+ });
+ row.SetExtraData("att", tag.Attributes[i]);
+ tm.Rows.Add(row);
+ }
+ scAttributesValue.Panel1.Expanded = true;
+ }
+ else
+ {
+ scAttributesValue.Panel1.Expanded = false;
+ }
+ txtValue.Text = el.Value;
+ }
+ }
+
+ private void RecursiveLoadElement(MarkupElement el, TreeModelRow parent)
+ {
+ TreeModelRow row = new TreeModelRow(new TreeModelRowColumn[]
+ {
+ new TreeModelRowColumn(tm.Columns[0], el.Name),
+ new TreeModelRowColumn(tm.Columns[1], el.Value)
+ });
+
+ if (el is MarkupContainerElement)
+ {
+ MarkupContainerElement ct = (el as MarkupContainerElement);
+ for (int i = 0; i < ct.Elements.Count; i++)
+ {
+ RecursiveLoadElement(ct.Elements[i], row);
+ }
+ }
+
+ if (parent == null)
+ {
+ tm.Rows.Add(row);
+ }
+ else
+ {
+ parent.Rows.Add(row);
+ }
+ }
+ }
+}
diff --git a/Libraries/UniversalEditor.UserInterface/UniversalEditor.UserInterface.csproj b/Libraries/UniversalEditor.UserInterface/UniversalEditor.UserInterface.csproj
index b45553ae..ebd7c8ea 100644
--- a/Libraries/UniversalEditor.UserInterface/UniversalEditor.UserInterface.csproj
+++ b/Libraries/UniversalEditor.UserInterface/UniversalEditor.UserInterface.csproj
@@ -131,6 +131,7 @@
+
@@ -185,6 +186,7 @@
+