title: System.StackOverflowException on InlineUIContainer deletion
body: <p>So, I have a RichTextBox which can contain one or more InlineUIContainer containing a small UserControl.
  When one of them is deleted, a StackOverflowException is directly thrown (none of my code run between the Backspace press and the exception).</p>
  <p>The exception is raised in internal code, I managed to recover the StackTrace thanks to WinDbg and here is the important part of the result :</p>
  <p><div class="snippet" data-lang="js" data-hide="true" data-console="true" data-babel="false">
  <div class="snippet-code snippet-currently-hidden">
  <pre class="snippet-code-html lang-html prettyprint-override"><code>...
  00bce210 51048111 System.Windows.Markup.Primitives.MarkupWriter.RecordNamespaces(Scope, System.Windows.Markup.Primitives.MarkupObject, System.Windows.Markup.IValueSerializerContext, Boolean)
  00bce25c 51048111 System.Windows.Markup.Primitives.MarkupWriter.RecordNamespaces(Scope, System.Windows.Markup.Primitives.MarkupObject, System.Windows.Markup.IValueSerializerContext, Boolean)
  00bce2a8 51048111 System.Windows.Markup.Primitives.MarkupWriter.RecordNamespaces(Scope, System.Windows.Markup.Primitives.MarkupObject, System.Windows.Markup.IValueSerializerContext, Boolean)
  00bce2f4 51048111 System.Windows.Markup.Primitives.MarkupWriter.RecordNamespaces(Scope, System.Windows.Markup.Primitives.MarkupObject, System.Windows.Markup.IValueSerializerContext, Boolean)
  00bce340 51048111 System.Windows.Markup.Primitives.MarkupWriter.RecordNamespaces(Scope, System.Windows.Markup.Primitives.MarkupObject, System.Windows.Markup.IValueSerializerContext, Boolean)
  00bce38c 51048111 System.Windows.Markup.Primitives.MarkupWriter.RecordNamespaces(Scope, System.Windows.Markup.Primitives.MarkupObject, System.Windows.Markup.IValueSerializerContext, Boolean)
  00bce3d8 5104829a System.Windows.Markup.Primitives.MarkupWriter.WriteItem(System.Windows.Markup.Primitives.MarkupObject)
  00bce3f0 51047ebd System.Windows.Markup.Primitives.MarkupWriter.SaveAsXml(System.Xml.XmlWriter, System.Windows.Markup.Primitives.MarkupObject)
  00bce41c 51047e15 System.Windows.Markup.Primitives.MarkupWriter.SaveAsXml(System.Xml.XmlWriter, System.Object)
  00bce428 51024246 System.Windows.Markup.XamlWriter.Save(System.Object, System.IO.TextWriter)
  00bce43c 510241c6 System.Windows.Markup.XamlWriter.Save(System.Object)
  00bce46c 51132783 System.Windows.Documents.TextTreeDeleteContentUndoUnit.CopyObjectNode(System.Windows.Documents.TextTreeObjectNode, ContentContainer ByRef)
  00bce484 511325c8 System.Windows.Documents.TextTreeDeleteContentUndoUnit.CopyContent(System.Windows.Documents.TextTreeNode, System.Windows.Documents.TextTreeNode)
  00bce4ac 5113290e System.Windows.Documents.TextTreeDeleteContentUndoUnit.CopyElementNode(System.Windows.Documents.TextTreeTextElementNode, ContentContainer ByRef)
  00bce4dc 51132632 System.Windows.Documents.TextTreeDeleteContentUndoUnit.CopyContent(System.Windows.Documents.TextTreeNode, System.Windows.Documents.TextTreeNode)
  00bce504 511323a0 System.Windows.Documents.TextTreeDeleteContentUndoUnit..ctor(System.Windows.Documents.TextContainer, System.Windows.Documents.TextPointer, System.Windows.Documents.TextPointer)
  00bce52c 51406de0 System.Windows.Documents.TextTreeUndo.CreateDeleteContentUndoUnit(System.Windows.Documents.TextContainer, System.Windows.Documents.TextPointer, System.Windows.Documents.TextPointer)
  00bce548 50729cc7 System.Windows.Documents.TextContainer.DeleteContentInternal(System.Windows.Documents.TextPointer, System.Windows.Documents.TextPointer)
  00bce57c 50728c51 System.Windows.Documents.TextRangeEdit.DeleteContentBetweenPositions(System.Windows.Documents.TextPointer, System.Windows.Documents.TextPointer)
  00bce590 50728bdc System.Windows.Documents.TextRangeEdit.DeleteEquiScopedContent(System.Windows.Documents.TextPointer, System.Windows.Documents.TextPointer)
  00bce5c0 50728ae7 System.Windows.Documents.TextRangeEdit.DeleteParagraphContent(System.Windows.Documents.ITextPointer, System.Windows.Documents.ITextPointer)
  00bce5dc 50fe4172 System.Windows.Documents.TextRangeEditTables.DeleteContent(System.Windows.Documents.TextPointer, System.Windows.Documents.TextPointer)
  00bce620 50fa7fa1 System.Windows.Documents.TextPointer.System.Windows.Documents.ITextPointer.DeleteContentToPosition(System.Windows.Documents.ITextPointer)
  00bce644 5103afb6 System.Windows.Documents.TextRangeBase.SetText(System.Windows.Documents.ITextRange, System.String)
  00bce68c 50fdf012 System.Windows.Documents.TextSelection.System.Windows.Documents.ITextRange.set_Text(System.String)
  00bce6b0 50fdb214 System.Windows.Documents.TextEditorTyping.OnBackspace(System.Object, System.Windows.Input.ExecutedRoutedEventArgs)</code></pre>
  </div>
  </div>
  </p>
  <p>And then it's 13000 more calls to MarkupWriter.RecordNamespaces until the exception. I did some research and when the InlineUIContainer is deleted, the framework tries to serialize it as XAML in order to be able to perform an Undo command. But in this case, the serialization is looping on the MarkupWriter.RecordNamespaces call.</p>
  <p>Because it's internal code, I don't know how to prevent this loop. What comes to my mind is to completly prevent the serialization of this InlineUIContainer, but I haven't found a way to do so.</p>
  <p>Is there one ?</p>
  <p><strong>EDIT :</strong></p>
  <p>As requested, here is the definition of the RichTextBox and the UserControl.</p>
  <p><strong>CurveFormulaTextBox.xaml</strong></p>
  <pre><code>&lt;UserControl x:Class=&quot;StruCAT.Views.CurveFormulaTextBox&quot;
               xmlns=&quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
               xmlns:x=&quot;http://schemas.microsoft.com/winfx/2006/xaml&quot;
               xmlns:d=&quot;http://schemas.microsoft.com/expression/blend/2008&quot;
               xmlns:mc=&quot;http://schemas.openxmlformats.org/markup-compatibility/2006&quot;
               xmlns:prop=&quot;clr-namespace:StruCAT.Properties&quot;
               xmlns:viewModels=&quot;clr-namespace:StruCAT.ViewModels&quot;
               x:Name=&quot;ThisCurveFormulaTextBox&quot;
               d:DataContext=&quot;{x:Type viewModels:ParameterViewModel}&quot;
               DataContextChanged=&quot;UserControl_DataContextChanged&quot;
               mc:Ignorable=&quot;d&quot;&gt;
  
      &lt;DockPanel&gt;
          &lt;RichTextBox x:Name=&quot;RichTextBox&quot;
                       MinWidth=&quot;250&quot;
                       Padding=&quot;1&quot;
                       VerticalContentAlignment=&quot;Center&quot;
                       IsDocumentEnabled=&quot;True&quot;
                       LostFocus=&quot;RichTextBox_LostFocus&quot;
                       PreviewKeyDown=&quot;RichTextBox_PreviewKeyDown&quot;
                       SelectionChanged=&quot;RichTextBox_SelectionChanged&quot;&gt;
              &lt;RichTextBox.Document&gt;
                  &lt;FlowDocument LineHeight=&quot;24&quot; PageWidth=&quot;10000&quot;&gt;
                      &lt;Paragraph x:Name=&quot;Paragraph&quot; Padding=&quot;0,0,0,0&quot; /&gt;
                  &lt;/FlowDocument&gt;
              &lt;/RichTextBox.Document&gt;
          &lt;/RichTextBox&gt;
          &lt;Popup x:Name=&quot;InsertionPopup&quot;
                 AllowsTransparency=&quot;True&quot;
                 IsOpen=&quot;{Binding IsFocused, ElementName=RichTextBox, Mode=OneWay}&quot;
                 PlacementTarget=&quot;{Binding ElementName=RichTextBox}&quot;&gt;
              &lt;StackPanel&gt;
                  &lt;StackPanel.Effect&gt;
                      &lt;DropShadowEffect BlurRadius=&quot;2&quot;
                                        Opacity=&quot;0.5&quot;
                                        ShadowDepth=&quot;0&quot; /&gt;
                  &lt;/StackPanel.Effect&gt;
                  &lt;Polygon HorizontalAlignment=&quot;Center&quot;
                           Fill=&quot;White&quot;
                           Points=&quot;4,0 0,8, 8,8&quot; /&gt;
                  &lt;Border Margin=&quot;1,0,1,1&quot;
                          Padding=&quot;1&quot;
                          Background=&quot;White&quot;
                          BorderThickness=&quot;0&quot;
                          CornerRadius=&quot;3&quot;&gt;
                      &lt;StackPanel Orientation=&quot;Horizontal&quot;&gt;
                          &lt;Button Margin=&quot;0&quot;
                                  Padding=&quot;1,1,0,0&quot;
                                  Content=&quot;{StaticResource CurveIcon}&quot;
                                  PreviewMouseLeftButtonDown=&quot;InsertCurve&quot;
                                  Style=&quot;{StaticResource CustomButton}&quot;
                                  ToolTip=&quot;{x:Static prop:Resources.AddCurve}&quot; /&gt;
                          &lt;Button Margin=&quot;0&quot;
                                  Content=&quot;{StaticResource VariableIcon}&quot;
                                  PreviewMouseLeftButtonDown=&quot;InsertVariable&quot;
                                  Style=&quot;{StaticResource CustomButton}&quot;
                                  ToolTip=&quot;{x:Static prop:Resources.AddVariable}&quot; /&gt;
                      &lt;/StackPanel&gt;
                  &lt;/Border&gt;
              &lt;/StackPanel&gt;
          &lt;/Popup&gt;
      &lt;/DockPanel&gt;
  &lt;/UserControl&gt;
  </code></pre>
  <p><strong>CurveFormulaTextBox.xaml.cs</strong></p>
  <pre><code>using StruCAT.ViewModels;
  using System.Linq;
  using System.Text;
  using System.Text.RegularExpressions;
  using System.Windows;
  using System.Windows.Controls;
  using System.Windows.Documents;
  using System.Windows.Input;
  
  namespace StruCAT.Views
  {
      /// &lt;summary&gt;
      /// Logique d'interaction pour CurveFormulaTextBox.xaml
      /// &lt;/summary&gt;
      public partial class CurveFormulaTextBox : UserControl
      {
          public CurveFormulaTextBox()
          {
              InitializeComponent();
          }
  
          public bool Working { get; set; } = false;
  
          public string Formula
          {
              get { return (string)GetValue(FormulaProperty); }
              set { SetValue(FormulaProperty, value); }
          }
          public static readonly DependencyProperty FormulaProperty = DependencyProperty.Register(&quot;Formula&quot;, typeof(string), typeof(CurveFormulaTextBox), new PropertyMetadata(&quot;&quot;, FormulaChanged));
  
          private static void FormulaChanged(object sender, DependencyPropertyChangedEventArgs e)
          {
              var cftb = (CurveFormulaTextBox)sender;
              if (e.NewValue != null &amp;&amp; !cftb.Working)
                  cftb.FillParagraph();
          }
  
          private void UpdateFormula()
          {
              Working = true;
              var formula = &quot;&quot;;
              foreach (var inline in Paragraph.Inlines)
              {
                  if (inline.GetType() == typeof(Run))
                      formula += ((Run)inline).Text;
                  else if (inline.GetType() == typeof(InlineUIContainer) &amp;&amp; ((InlineUIContainer)inline).Child.GetType() == typeof(KeywordComboBox))
                  {
                      var kw = ((KeywordComboBox)((InlineUIContainer)inline).Child).SelectedKeyword;
                      if (kw != null)
                          formula += &quot;{&quot; + kw.Model.Type + &quot;;&quot; + kw.Model.ID + &quot;}&quot;;
                  }
              }
              Formula = formula;
              Working = false;
          }
  
          public void FillParagraph()
          {
              Working = true;
              foreach (var match in Regex.Matches(Formula, &quot;{.*?}|[^{}]+&quot;))
              {
                  if (match.ToString().StartsWith(&quot;{&quot;))
                  {
                      var targetType = match.ToString().Replace(&quot;{&quot;, &quot;&quot;).Replace(&quot;}&quot;, &quot;&quot;).Trim().Split(';')[0];
                      var keywordID = match.ToString().Replace(&quot;{&quot;, &quot;&quot;).Replace(&quot;}&quot;, &quot;&quot;).Trim().Split(';')[1];
  
                      var cbo = CreateKCB(targetType);
                      cbo.SelectedKeyword = (DataContext as ParameterViewModel).Parent.Parent.Parent.Keywords.FirstOrDefault(x =&gt; x.Model.ID == keywordID);
                      Paragraph.Inlines.Add(cbo);
                  }
                  else
                  {
                      Paragraph.Inlines.Add(new Run(match.ToString()));
                  }
              }
              Working = false;
          }
  
          private KeywordComboBox CreateKCB(string type)
          {
              var kcb = new KeywordComboBox() { Type = type, DataContext = this.DataContext };
              kcb.SelectionChanged += () =&gt; UpdateFormula();
              return kcb;
          }
  
          private void UserControl_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e) { 
              FillParagraph(); 
          }
  
          private void RichTextBox_LostFocus(object sender, RoutedEventArgs e) 
          { 
              UpdateFormula(); 
          }
  
          private void RichTextBox_PreviewKeyDown(object sender, KeyEventArgs e) 
          { 
              if (e.Key == Key.Enter) e.Handled = true; 
          }
  
          private void RichTextBox_SelectionChanged(object sender, RoutedEventArgs e)
          {
              Rect positionRect = RichTextBox.CaretPosition.GetCharacterRect(LogicalDirection.Backward);
              InsertionPopup.HorizontalOffset = positionRect.Left - ((FrameworkElement)InsertionPopup.Child).ActualWidth / 2.0;
              UpdateFormula();
          }
  
          private void InsertCurve(object sender, MouseButtonEventArgs e)
          {
              new InlineUIContainer(CreateKCB(&quot;Curve&quot;), RichTextBox.CaretPosition);
          }
  
          private void InsertVariable(object sender, MouseButtonEventArgs e)
          {
              new InlineUIContainer(CreateKCB(&quot;Float&quot;), RichTextBox.CaretPosition);
          }
  
  
      }
  }
  </code></pre>
  <p><strong>KeywordComboBox.xaml</strong></p>
  <pre><code>&lt;UserControl x:Class=&quot;StruCAT.Views.KeywordComboBox&quot;
               xmlns=&quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
               xmlns:x=&quot;http://schemas.microsoft.com/winfx/2006/xaml&quot;
               xmlns:d=&quot;http://schemas.microsoft.com/expression/blend/2008&quot;
               xmlns:mc=&quot;http://schemas.openxmlformats.org/markup-compatibility/2006&quot;
               xmlns:viewModels=&quot;clr-namespace:StruCAT.ViewModels&quot;
               x:Name=&quot;ThisKeywordCombobox&quot;
               Margin=&quot;1,1,1,-6&quot;
               d:DataContext=&quot;{x:Type viewModels:ParameterViewModel}&quot;
               mc:Ignorable=&quot;d&quot;&gt;
  
      &lt;DockPanel Height=&quot;22&quot;&gt;
          &lt;Border Background=&quot;WhiteSmoke&quot;
                  BorderBrush=&quot;Silver&quot;
                  BorderThickness=&quot;1,1,0,1&quot;
                  CornerRadius=&quot;2,0,0,2&quot;
                  UseLayoutRounding=&quot;True&quot;&gt;
              &lt;ContentPresenter DockPanel.Dock=&quot;Left&quot;&gt;
                  &lt;ContentPresenter.Style&gt;
                      &lt;Style TargetType=&quot;{x:Type ContentPresenter}&quot;&gt;
                          &lt;Setter Property=&quot;Content&quot; Value=&quot;{StaticResource VariableIcon}&quot; /&gt;
                          &lt;Style.Triggers&gt;
                              &lt;DataTrigger Binding=&quot;{Binding Type, ElementName=ThisKeywordCombobox}&quot; Value=&quot;Curve&quot;&gt;
                                  &lt;Setter Property=&quot;Content&quot; Value=&quot;{StaticResource CurveIcon}&quot; /&gt;
                              &lt;/DataTrigger&gt;
                          &lt;/Style.Triggers&gt;
                      &lt;/Style&gt;
                  &lt;/ContentPresenter.Style&gt;
              &lt;/ContentPresenter&gt;
          &lt;/Border&gt;
          &lt;ComboBox Padding=&quot;3,3,0,3&quot;
                    DisplayMemberPath=&quot;Name&quot;
                    IsEnabled=&quot;{Binding Path=ItemsSource, RelativeSource={RelativeSource Self}, Converter={StaticResource EmptyToFalseConverter}}&quot;
                    IsSynchronizedWithCurrentItem=&quot;True&quot;
                    SelectedItem=&quot;{Binding SelectedKeyword, ElementName=ThisKeywordCombobox, UpdateSourceTrigger=PropertyChanged}&quot;
                    SelectionChanged=&quot;ComboBox_SelectionChanged&quot;&gt;
              &lt;ComboBox.ItemsSource&gt;
                  &lt;MultiBinding Converter=&quot;{StaticResource KeywordsFilter}&quot;&gt;
                      &lt;Binding Path=&quot;Parent.Parent.Parent.Keywords&quot; /&gt;
                      &lt;Binding ElementName=&quot;ThisKeywordCombobox&quot; Path=&quot;Type&quot; /&gt;
                      &lt;Binding Path=&quot;Parent.Parent.KeywordViewModel&quot; /&gt;
                      &lt;Binding Path=&quot;Parent.Keywords&quot; /&gt;
                      &lt;!--  USED ONLY TO TRIGGER UPDATE  --&gt;
                      &lt;Binding Path=&quot;Parent.Parent.Parent.Keywords.Count&quot; /&gt;
                      &lt;Binding Path=&quot;Parent.Keywords.Count&quot; /&gt;
                  &lt;/MultiBinding&gt;
              &lt;/ComboBox.ItemsSource&gt;
          &lt;/ComboBox&gt;
      &lt;/DockPanel&gt;
  &lt;/UserControl&gt;
  </code></pre>
  <p><strong>KeywordComboBox.xaml.cs</strong></p>
  <pre><code>using StruCAT.ViewModels;
  using System.Windows;
  using System.Windows.Controls;
  
  namespace StruCAT.Views
  {
      /// &lt;summary&gt;
      /// Logique d'interaction pour KeywordComboBox.xaml
      /// &lt;/summary&gt;
      public partial class KeywordComboBox : UserControl
      {
          public KeywordComboBox()
          {
              InitializeComponent();
          }
  
          public KeywordViewModel SelectedKeyword
          {
              get { return (KeywordViewModel)GetValue(SelectedKeywordProperty); }
              set { SetValue(SelectedKeywordProperty, value); }
          }
          public static readonly DependencyProperty SelectedKeywordProperty = DependencyProperty.Register(&quot;SelectedKeyword&quot;, typeof(KeywordViewModel), typeof(KeywordComboBox), new PropertyMetadata(null));
  
          public string Type
          {
              get { return (string)GetValue(TypeProperty); }
              set { SetValue(TypeProperty, value); }
          }
          public static readonly DependencyProperty TypeProperty = DependencyProperty.Register(&quot;Type&quot;, typeof(string), typeof(KeywordComboBox), new PropertyMetadata(&quot;Float&quot;));
  
          private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
          {
              SelectionChanged();
          }
  
          public delegate void SelectionChange();
          public event SelectionChange SelectionChanged;
  
      }
  }
  </code></pre>
  <p>A first solution provided in a comment which has disappeared since (?) is to completly prevent the Undo command by setting UndoLimit of the RichTextBox to 0. It effectively prevents the exception on deletion of an InlineUIContainer. If there is no other solution I'll use this one.</p>