예제 #1
0
        private static void OnXamlStringChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            TextBlock tb = d as TextBlock;

            if (tb == null)
            {
                return;
            }

            string xamlString = e.NewValue as string;

            if (string.IsNullOrEmpty(xamlString))
            {
                return;
            }

            InlineCollection inlineCollection = CreateInlineCollection(xamlString);

            if (inlineCollection == null || inlineCollection.Count == 0)
            {
                return;
            }

            Inline[] inlines = new Inline[inlineCollection.Count];
            inlineCollection.CopyTo(inlines, 0);

            PopulateTextBlockInlines(tb, inlines);
        }
        /// <summary>
        /// Event handler for KeyDown event to auto-detect hyperlinks on space, enter and backspace keys.
        /// </summary>
        private static void OnKeyDown(object sender, KeyEventArgs e)
        {
            var myRichTextBox = (MyRichTextBox)sender;

            if (e.Key != Key.Space && e.Key != Key.Back && e.Key != Key.Return)
            {
                return;
            }

            if (!myRichTextBox.Selection.IsEmpty)
            {
                myRichTextBox.Selection.Text = String.Empty;
            }

            TextPointer caretPosition = myRichTextBox.Selection.Start;

            if (e.Key == Key.Space || e.Key == Key.Return)
            {
                TextPointer wordStartPosition;
                string      word = GetPreceedingWordInParagraph(caretPosition, out wordStartPosition);

                if (word == "www.microsoft.com")
                // A real app would need a more sophisticated RegEx match expression for hyperlinks.
                {
                    // Insert hyperlink element at word boundaries.
                    var start = wordStartPosition.GetPositionAtOffset(0, LogicalDirection.Backward);
                    var end   = caretPosition.GetPositionAtOffset(0, LogicalDirection.Forward);

                    if (start != null)
                    {
                        if (end != null)
                        {
                            new Hyperlink(start
                                          , end);
                        }
                    }

                    // No need to update RichTextBox caret position,
                    // since we only inserted a Hyperlink ElementEnd following current caretPosition.
                    // Subsequent handling of space input by base RichTextBox will update selection.
                }
            }
            else // Key.Back
            {
                TextPointer backspacePosition = caretPosition.GetNextInsertionPosition(LogicalDirection.Backward);
                Hyperlink   hyperlink;
                if (backspacePosition != null &&
                    IsHyperlinkBoundaryCrossed(caretPosition, backspacePosition, out hyperlink))
                {
                    // Remember caretPosition with forward gravity. This is necessary since we are going to delete
                    // the hyperlink element preceeding caretPosition and after deletion current caretPosition
                    // (with backward gravity) will follow content preceeding the hyperlink.
                    // We want to remember content following the hyperlink to set new caret position at.

                    TextPointer newCaretPosition = caretPosition.GetPositionAtOffset(0, LogicalDirection.Forward);

                    // Deleting the hyperlink is done using logic below.

                    // 1. Copy its children Inline to a temporary array.
                    InlineCollection hyperlinkChildren = hyperlink.Inlines;
                    var 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's local formatting properties to inlines (which are now outside hyperlink scope).
                    LocalValueEnumerator localProperties = hyperlink.GetLocalValueEnumerator();
                    var inlineRange = new TextRange(inlines[0].ContentStart, inlines[inlines.Length - 1].ContentEnd);

                    while (localProperties.MoveNext())
                    {
                        LocalValueEntry    property = localProperties.Current;
                        DependencyProperty dp       = property.Property;
                        object             value    = property.Value;

                        if (!dp.ReadOnly &&
                            dp != Inline.TextDecorationsProperty && // Ignore hyperlink defaults.
                            dp != TextElement.ForegroundProperty &&
                            !IsHyperlinkProperty(dp))
                        {
                            inlineRange.ApplyPropertyValue(dp, value);
                        }
                    }

                    // 4. Delete the (empty) hyperlink element.
                    if (hyperlink.SiblingInlines != null)
                    {
                        hyperlink.SiblingInlines.Remove(hyperlink);
                    }

                    // 5. Update selection, since we deleted Hyperlink element and caretPosition was at that Hyperlink's end boundary.
                    if (newCaretPosition != null)
                    {
                        myRichTextBox.Selection.Select(newCaretPosition, newCaretPosition);
                    }
                }
            }
        }
예제 #3
0
        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);
            }
        }