diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/InlineObjectRun.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/InlineObjectRun.cs
index b3c76914e3..1837b2b179 100644
--- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/InlineObjectRun.cs
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/InlineObjectRun.cs
@@ -41,7 +41,7 @@ namespace ICSharpCode.AvalonEdit.Rendering
// remove inline object if its already added, can happen e.g. when recreating textrun for word-wrapping
// TODO: certainly the text view should handle this internally? external code might want to use InlineObjectRun,
// but doesn't have access to textLayer.RemoveInlineObject
- context.TextView.textLayer.RemoveInlineObject(this.Element);
+ context.TextView.RemoveInlineObject(this.Element);
return new InlineObjectRun(1, this.TextRunProperties, this.Element);
}
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/TextLayer.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/TextLayer.cs
index beae3ba496..e2b06e337b 100644
--- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/TextLayer.cs
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/TextLayer.cs
@@ -24,6 +24,11 @@ namespace ICSharpCode.AvalonEdit.Rendering
///
sealed class TextLayer : Layer
{
+ ///
+ /// the index of the text layer in the layers collection
+ ///
+ internal int index;
+
public TextLayer(TextView textView) : base(textView, KnownLayer.Text)
{
}
@@ -33,89 +38,5 @@ namespace ICSharpCode.AvalonEdit.Rendering
base.OnRender(drawingContext);
textView.RenderTextLayer(drawingContext);
}
-
- #region Inline object handling
- internal List inlineObjects = new List();
-
- ///
- /// Adds a new inline object.
- ///
- internal void AddInlineObject(InlineObjectRun inlineObject)
- {
- inlineObjects.Add(inlineObject);
- AddVisualChild(inlineObject.Element);
- inlineObject.Element.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
- }
-
- List visualLinesWithOutstandingInlineObjects = new List();
-
- internal void RemoveInlineObjects(VisualLine visualLine)
- {
- // Delay removing inline objects:
- // A document change immediately invalidates affected visual lines, but it does not
- // cause an immediate redraw.
- // To prevent inline objects from flickering when they are recreated, we delay removing
- // inline objects until the next redraw.
- visualLinesWithOutstandingInlineObjects.Add(visualLine);
- }
-
- internal void RemoveInlineObjectsNow()
- {
- inlineObjects.RemoveAll(
- ior => {
- if (visualLinesWithOutstandingInlineObjects.Contains(ior.VisualLine)) {
- RemoveInlineObjectRun(ior);
- return true;
- }
- return false;
- });
- visualLinesWithOutstandingInlineObjects.Clear();
- }
-
- // Remove InlineObjectRun.Element from TextLayer.
- // Caller of RemoveInlineObjectRun will remove it from inlineObjects collection.
- void RemoveInlineObjectRun(InlineObjectRun ior)
- {
- if (ior.Element.IsKeyboardFocusWithin) {
- // When the inline element that has the focus is removed, WPF will reset the
- // focus to the main window without raising appropriate LostKeyboardFocus events.
- // To work around this, we manually set focus to the next focusable parent.
- UIElement element = textView;
- while (element != null && !element.Focusable) {
- element = VisualTreeHelper.GetParent(element) as UIElement;
- }
- if (element != null)
- Keyboard.Focus(element);
- }
- ior.VisualLine = null;
- RemoveVisualChild(ior.Element);
- }
-
- ///
- /// Removes the inline object that displays the specified UIElement.
- ///
- internal void RemoveInlineObject(UIElement element)
- {
- inlineObjects.RemoveAll(
- ior => {
- if (ior.Element == element) {
- RemoveInlineObjectRun(ior);
- return true;
- }
- return false;
- });
- }
-
- ///
- protected override int VisualChildrenCount {
- get { return inlineObjects.Count; }
- }
-
- ///
- protected override Visual GetVisualChild(int index)
- {
- return inlineObjects[index].Element;
- }
- #endregion
}
}
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/TextView.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/TextView.cs
index 903fc0f5c7..be9f6c9fd2 100644
--- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/TextView.cs
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/TextView.cs
@@ -53,7 +53,7 @@ namespace ICSharpCode.AvalonEdit.Rendering
this.Options = new TextEditorOptions();
Debug.Assert(singleCharacterElementGenerator != null); // assert that the option change created the builtin element generators
- layers = new UIElementCollection(this, this);
+ layers = new LayerCollection(this);
InsertLayer(textLayer, KnownLayer.Text, LayerInsertionPosition.Replace);
}
#endregion
@@ -293,7 +293,7 @@ namespace ICSharpCode.AvalonEdit.Rendering
#region Layers
internal readonly TextLayer textLayer;
- readonly UIElementCollection layers;
+ readonly LayerCollection layers;
///
/// Gets the list of layers displayed in the text view.
@@ -302,6 +302,47 @@ namespace ICSharpCode.AvalonEdit.Rendering
get { return layers; }
}
+ sealed class LayerCollection : UIElementCollection
+ {
+ readonly TextView textView;
+
+ public LayerCollection(TextView textView)
+ : base(textView, textView)
+ {
+ this.textView = textView;
+ }
+
+ public override void Clear()
+ {
+ base.Clear();
+ textView.LayersChanged();
+ }
+
+ public override int Add(UIElement element)
+ {
+ int r = base.Add(element);
+ textView.LayersChanged();
+ return r;
+ }
+
+ public override void RemoveAt(int index)
+ {
+ base.RemoveAt(index);
+ textView.LayersChanged();
+ }
+
+ public override void RemoveRange(int index, int count)
+ {
+ base.RemoveRange(index, count);
+ textView.LayersChanged();
+ }
+ }
+
+ void LayersChanged()
+ {
+ textLayer.index = layers.IndexOf(textLayer);
+ }
+
///
/// Inserts a new layer at a position specified relative to an existing layer.
///
@@ -351,18 +392,99 @@ namespace ICSharpCode.AvalonEdit.Rendering
///
protected override int VisualChildrenCount {
- get { return layers.Count; }
+ get { return layers.Count + inlineObjects.Count; }
}
///
protected override Visual GetVisualChild(int index)
{
- return layers[index];
+ int cut = textLayer.index + 1;
+ if (index < cut)
+ return layers[index];
+ else if (index < cut + inlineObjects.Count)
+ return inlineObjects[index - cut].Element;
+ else
+ return layers[index - inlineObjects.Count];
}
///
protected override System.Collections.IEnumerator LogicalChildren {
- get { return layers.GetEnumerator(); }
+ get {
+ return inlineObjects.Select(io => io.Element).Concat(layers.Cast()).GetEnumerator();
+ }
+ }
+ #endregion
+
+ #region Inline object handling
+ internal List inlineObjects = new List();
+
+ ///
+ /// Adds a new inline object.
+ ///
+ internal void AddInlineObject(InlineObjectRun inlineObject)
+ {
+ inlineObjects.Add(inlineObject);
+ AddVisualChild(inlineObject.Element);
+ inlineObject.Element.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
+ }
+
+ List visualLinesWithOutstandingInlineObjects = new List();
+
+ internal void RemoveInlineObjects(VisualLine visualLine)
+ {
+ // Delay removing inline objects:
+ // A document change immediately invalidates affected visual lines, but it does not
+ // cause an immediate redraw.
+ // To prevent inline objects from flickering when they are recreated, we delay removing
+ // inline objects until the next redraw.
+ visualLinesWithOutstandingInlineObjects.Add(visualLine);
+ }
+
+ internal void RemoveInlineObjectsNow()
+ {
+ inlineObjects.RemoveAll(
+ ior => {
+ if (visualLinesWithOutstandingInlineObjects.Contains(ior.VisualLine)) {
+ RemoveInlineObjectRun(ior);
+ return true;
+ }
+ return false;
+ });
+ visualLinesWithOutstandingInlineObjects.Clear();
+ }
+
+ // Remove InlineObjectRun.Element from TextLayer.
+ // Caller of RemoveInlineObjectRun will remove it from inlineObjects collection.
+ void RemoveInlineObjectRun(InlineObjectRun ior)
+ {
+ if (ior.Element.IsKeyboardFocusWithin) {
+ // When the inline element that has the focus is removed, WPF will reset the
+ // focus to the main window without raising appropriate LostKeyboardFocus events.
+ // To work around this, we manually set focus to the next focusable parent.
+ UIElement element = this;
+ while (element != null && !element.Focusable) {
+ element = VisualTreeHelper.GetParent(element) as UIElement;
+ }
+ if (element != null)
+ Keyboard.Focus(element);
+ }
+ ior.VisualLine = null;
+ RemoveVisualChild(ior.Element);
+ }
+
+ ///
+ /// Removes the inline object that displays the specified UIElement.
+ ///
+ internal void RemoveInlineObject(UIElement element)
+ {
+ inlineObjects.RemoveAll(
+ ior => {
+ if (ior.Element == element) {
+ RemoveInlineObjectRun(ior);
+ return true;
+ }
+ return false;
+ });
}
#endregion
@@ -495,7 +617,7 @@ namespace ICSharpCode.AvalonEdit.Rendering
foreach (TextLine textLine in visualLine.TextLines) {
textLine.Dispose();
}
- textLayer.RemoveInlineObjects(visualLine);
+ RemoveInlineObjects(visualLine);
}
#endregion
@@ -676,7 +798,7 @@ namespace ICSharpCode.AvalonEdit.Rendering
ClearVisualLines();
lastAvailableSize = availableSize;
- textLayer.RemoveInlineObjectsNow();
+ RemoveInlineObjectsNow();
foreach (UIElement layer in layers) {
layer.Measure(availableSize);
@@ -699,7 +821,7 @@ namespace ICSharpCode.AvalonEdit.Rendering
}
}
- textLayer.RemoveInlineObjectsNow();
+ RemoveInlineObjectsNow();
maxWidth += AdditionalHorizontalScrollAmount;
double heightTreeHeight = this.DocumentHeight;
@@ -946,7 +1068,7 @@ namespace ICSharpCode.AvalonEdit.Rendering
foreach (var span in textLine.GetTextRunSpans()) {
InlineObjectRun inline = span.Value as InlineObjectRun;
if (inline != null && inline.VisualLine != null) {
- Debug.Assert(textLayer.inlineObjects.Contains(inline));
+ Debug.Assert(inlineObjects.Contains(inline));
double distance = textLine.GetDistanceFromCharacterHit(new CharacterHit(offset, 0));
inline.Element.Arrange(new Rect(new Point(pos.X + distance, pos.Y), inline.Element.DesiredSize));
}
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/VisualLineTextSource.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/VisualLineTextSource.cs
index fa6fa6f1c2..97d0f9029e 100644
--- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/VisualLineTextSource.cs
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/VisualLineTextSource.cs
@@ -42,7 +42,7 @@ namespace ICSharpCode.AvalonEdit.Rendering
InlineObjectRun inlineRun = run as InlineObjectRun;
if (inlineRun != null) {
inlineRun.VisualLine = VisualLine;
- TextView.textLayer.AddInlineObject(inlineRun);
+ TextView.AddInlineObject(inlineRun);
}
return run;
}