private void RemoveHyperlinkFormat() { TextPointer caretPosition = Selection.Start; TextPointer backspacePosition = caretPosition.GetNextInsertionPosition(LogicalDirection.Backward); Hyperlink hyperlink = default(Hyperlink); try { if (backspacePosition != null && IsHyperlinkBoundaryCrossed(caretPosition, backspacePosition, ref hyperlink)) { // Remember caretPosition with forward gravity. This is necessary since we are going to delete // the hyperlink element preceding caretPosition and after deletion current caretPosition // (with backward gravity) will follow content preceding the hyperlink. // We want to remember content following the hyperlink to set new caret position at. TextPointer newCaretPosition = caretPosition.GetPositionAtOffset(0, LogicalDirection.Forward); // 1. Copy its children Inline to a temporary array InlineCollection hyperlinkChildren = hyperlink.Inlines; Inline[] inlines = new Inline[hyperlinkChildren.Count]; hyperlinkChildren.CopyTo(inlines, 0); // 2. Remove each child from parent hyperlink element and insert it after the hyperlink for (int i = inlines.Length - 1; i >= 0; i--) { hyperlinkChildren.Remove(inlines[i]); if (hyperlink.SiblingInlines != null) { hyperlink.SiblingInlines.InsertAfter(hyperlink, inlines[i]); } } // 3. Apply hyperlink local formatting properties to inlines (which are now outside hyperlink scope) LocalValueEnumerator localProperties = hyperlink.GetLocalValueEnumerator(); TextRange inlineRange = new TextRange(inlines[0].ContentStart, inlines[inlines.Length - 1].ContentEnd); while (localProperties.MoveNext()) { LocalValueEntry property = localProperties.Current; DependencyProperty dependencyProperty = property.Property; object value = property.Value; // Ignore hyperlink defaults if (dependencyProperty.ReadOnly == false && dependencyProperty.Equals(Inline.TextDecorationsProperty) == false && dependencyProperty.Equals(TextElement.ForegroundProperty) == false && dependencyProperty.Equals(BaseUriHelper.BaseUriProperty) == false && IsHyperlinkProperty(dependencyProperty) == false && dependencyProperty.Name.Equals("IsEnabled") == false) { inlineRange.ApplyPropertyValue(dependencyProperty, value); } } // 4. Delete the (empty) hyperlink element if (hyperlink.SiblingInlines != null) { hyperlink.RequestNavigate -= OnRequestNavigate; hyperlink.SiblingInlines.Remove(hyperlink); } // 5. Update selection, since we deleted Hyperlink element and caretPosition was at that hyperlink's end boundary Selection.Select(newCaretPosition, newCaretPosition); } } catch (Exception ex) { Log.Error("Error while removing hyperlink format: {EX}", ex); } }