wpf,能够复制文字 及自动识别URL超链接的TextBlock

using System;
using System.Collections.Generic;
using System.Diagnostics;
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;
using System.Windows.Media;

namespace SelectableTextBlock
{
    public class TextBlockSelect : TextBlock
    {
          TextPointer startpoz;
        TextPointer endpoz;
        MenuItem copyMenu;
        MenuItem selectAllMenu;

        public TextRange Selection { get; private set; }
        public bool HasSelection
        {
            get { return Selection != null && !Selection.IsEmpty; }
        }

        #region SelectionBrush

        public static readonly DependencyProperty SelectionBrushProperty =
            DependencyProperty.Register("SelectionBrush", typeof(Brush), typeof(TextBlockSelect),
                new FrameworkPropertyMetadata(Brushes.Orange));

        public Brush SelectionBrush
        {
            get { return (Brush)GetValue(SelectionBrushProperty); }
            set { SetValue(SelectionBrushProperty, value); }
        }

        #endregion

        public static readonly DependencyProperty Text2Property =
    DependencyProperty.Register("Text2", typeof(string), typeof(TextBlockSelect),
        new FrameworkPropertyMetadata(new PropertyChangedCallback(OnText2PropertyChanged)));

        public string Text2
        {
            get { return (string)GetValue(Text2Property); }
            set { SetValue(Text2Property, value); }
        }

        static void OnText2PropertyChanged(object sender, DependencyPropertyChangedEventArgs args)
        {
            if (sender != null && sender is TextBlockSelect)
            {
                TextBlockSelect view = (TextBlockSelect)sender;
                if (args != null && args.NewValue != null)
                {
                    string value = args.NewValue.ToString();
                    if (string.IsNullOrWhiteSpace(value))
                    {
                        view.Text = "";
                        view.Inlines.Clear();
                    }
                    else
                    {
                        view.AddInlines(value);
                    }
                }
                else
                {
                    view.Text = "";
                    view.Inlines.Clear();
                }
            }
        }

        static void link_Click(object sender, RoutedEventArgs e)
        {
            Hyperlink link = sender as Hyperlink;
            Process.Start(new ProcessStartInfo(link.NavigateUri.AbsoluteUri));
            //throw new NotImplementedException();
        }

        public void AddInlines(string value)
        {
            Regex urlregex = new Regex(@"((http|ftp|https)://)(([a-zA-Z0-9._-]+.[a-zA-Z]{2,6})|([0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}))(:[0-9]{1,4})*(/[a-zA-Z0-9&%_./-~-]*)?", RegexOptions.IgnoreCase | RegexOptions.Compiled);
            var ss = urlregex.Matches(value);
            List<Tuple<int, int, string>> urlList = new List<Tuple<int, int, string>>();
            foreach (Match item in ss)
            {
                Tuple<int, int, string> urlIndex = new Tuple<int, int, string>(value.IndexOf(item.Value), item.Value.Length, item.Value);
                urlList.Add(urlIndex);
            }

            if (urlList.Count > 0)
            {
                //urlList.Sort();
                for (int i = 0; i < urlList.Count; i++)
                {
                    if (i == 0)
                    {
                        string startValue = value.Substring(0, urlList[0].Item1);
                        if (string.IsNullOrEmpty(startValue))
                            startValue = " ";
                        this.Inlines.Add(new Run() { Text = startValue });

                        AddHyperlink(urlList[0].Item3);
                    }
                    else
                    {
                        int stratIndex = urlList[i - 1].Item1 + urlList[i - 1].Item2;
                        this.Inlines.Add(new Run() { Text = value.Substring(stratIndex, urlList[i].Item1 - stratIndex) });

                        AddHyperlink(urlList[i].Item3);
                    }

                    if (i == urlList.Count - 1)
                    {
                        string endValue = value.Substring(urlList[i].Item1 + urlList[i].Item2);
                        if (string.IsNullOrEmpty(endValue))
                            endValue = " ";
                        this.Inlines.Add(new Run() { Text = endValue });
                    }
                }
            }
            else
            {
                this.Inlines.Clear();
                this.Text = value;
            }
        }

        private void AddHyperlink(string value)
        {
            try
            {
                Hyperlink link = new Hyperlink();
                link.NavigateUri = new Uri(value);
                link.Click += link_Click;
                link.Inlines.Add(new Run() { Text = value });
                this.Inlines.Add(link);
            }
            catch {
                this.Inlines.Add(new Run() { Text = value });
            }
        }

        public TextBlockSelect()
        {
            Focusable = true;
            //InitMenu();
        }

        void InitMenu()
        {
            var contextMenu = new ContextMenu();
            ContextMenu = contextMenu;

            copyMenu = new MenuItem();
            copyMenu.Header = "复制";
            copyMenu.InputGestureText = "Ctrl + C";
            copyMenu.Click += (ss, ee) =>
            {
                Copy();
            };
            contextMenu.Items.Add(copyMenu);

            selectAllMenu = new MenuItem();
            selectAllMenu.Header = "全选";
            selectAllMenu.InputGestureText = "Ctrl + A";
            selectAllMenu.Click += (ss, ee) =>
            {
                SelectAll();
            };
            contextMenu.Items.Add(selectAllMenu);

            ContextMenuOpening += contextMenu_ContextMenuOpening;
        }

        void contextMenu_ContextMenuOpening(object sender, ContextMenuEventArgs e)
        {
            copyMenu.IsEnabled = HasSelection;
        }
        protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
        {
            Keyboard.Focus(this);
            ReleaseMouseCapture();
            base.OnMouseLeftButtonUp(e);
        }

        protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
        {
            var point = e.GetPosition(this);
            startpoz = GetPositionFromPoint(point, true);
            CaptureMouse();
            base.OnMouseLeftButtonDown(e);
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            if (IsMouseCaptured)
            {
                var point = e.GetPosition(this);
                endpoz = GetPositionFromPoint(point, true);

                ClearSelection();
                Selection = new TextRange(startpoz, endpoz);
                Selection.ApplyPropertyValue(TextElement.BackgroundProperty, SelectionBrush);
                CommandManager.InvalidateRequerySuggested();

                OnSelectionChanged(EventArgs.Empty);
            }

            base.OnMouseMove(e);
        }

        protected override void OnKeyUp(KeyEventArgs e)
        {
            if (Keyboard.Modifiers == ModifierKeys.Control)
            {
                if (e.Key == Key.C)
                    Copy();
                else if (e.Key == Key.A)
                    SelectAll();
            }

            base.OnKeyUp(e);
        }

        protected override void OnLostFocus(RoutedEventArgs e)
        {
            ClearSelection();
            //base.OnLostFocus(e);
        }

        public bool Copy()
        {
            if (HasSelection)
            {
                Clipboard.SetDataObject(Selection.Text);
                return true;
            }
            return false;
        }

        public void ClearSelection()
        {
            var contentRange = new TextRange(ContentStart, ContentEnd);
            contentRange.ApplyPropertyValue(TextElement.BackgroundProperty, null);
            Selection = null;
        }

        public void SelectAll()
        {
            Selection = new TextRange(ContentStart, ContentEnd);
            Selection.ApplyPropertyValue(TextElement.BackgroundProperty, SelectionBrush);
        }

        public event EventHandler SelectionChanged;

        protected virtual void OnSelectionChanged(EventArgs e)
        {
            var handler = this.SelectionChanged;
            if (handler != null)
                handler(this, e);
        }
    }


}


  在 WPF: 可以点击选择和复制文本的TextBlock 的基础上添加了对Url的识别。

原文地址:https://www.cnblogs.com/m7777/p/6233028.html