欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

wpf-利用装饰器制作 彩色字体+可选中+可复制 的textblock

程序员文章站 2022-06-07 15:16:11
...

效果如下图所示:
wpf-利用装饰器制作 彩色字体+可选中+可复制 的textblock
实现要点:

  • 彩色字体可以用TextBlock的Run实现
  • “可选中”可以通过装饰器实现
  • 注意鼠标事件处理

前台

<ScrollViewer Width="400" x:Name="colorScrollViewer" HorizontalScrollBarVisibility="Visible" >
    <TextBlock x:Name="colorSeq" ScrollViewer.CanContentScroll="True"
               VirtualizingPanel.IsVirtualizing="True" VirtualizingPanel.ScrollUnit="Pixel" 		
               VirtualizingPanel.VirtualizationMode="Recycling" 
               MouseLeftButtonDown="colorSeq_MouseLeftButtonDown"
               PreviewMouseLeftButtonDown="colorSeq_PreviewMouseLeftButtonDown"
               PreviewMouseLeftButtonUp="colorSeq_PreviewMouseLeftButtonUp"
               />
</ScrollViewer>

后台

    public partial class WPInfoWindow : Window
    {
        private Point _startMousePosition { set; get; }
        private TextPointer _startPt { set; get; }
        private TextBlockSelectedAdorner _tbsAdorner { set; get; }
        
        public WPInfoWindow()
        {
            InitializeComponent();
            string t = "";
            string[] dict = new string[] {"A","C","G","T" };
            // 搞点随机字符串
            Random rd = new Random();
            for (int i = 0; i < 4000; i++) {
                string c = dict[rd.Next(0, 4)];
                Run r = new Run();
                r.Text = c;
                // 给点不同的颜色
                switch (c) {
                    case "A":
                        r.Foreground = Brushes.Green;
                        break;
                    case "C":
                        r.Foreground = Brushes.Blue;
                        break;
                    case "G":
                        r.Foreground = Brushes.Black;
                        break;
                    case "T":
                        r.Foreground = Brushes.Red;
                        break;
                }
                this.colorSeq.Inlines.Add(r);
            }  
        }
...
        private void colorSeq_PreviewMouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            Point lastMousePosition = e.GetPosition(this.colorSeq);
            TextPointer tp = this.colorSeq.GetPositionFromPoint(lastMousePosition, true);
            TextRange tr = new TextRange(_startPt, tp);
            string selectedText = tr.Text;
            AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(this.colorSeq);
            Rect rect = new Rect(_startMousePosition.X, 0.0, lastMousePosition.X-_startMousePosition.X, 30);
            this._tbsAdorner = new TextBlockSelectedAdorner(this.colorSeq, rect);
            adornerLayer.Add(this._tbsAdorner);
            // 省去复制到剪贴板那步,自己想咋处理咋处理
            MessageBox.Show(selectedText);
        }

        private void colorSeq_PreviewMouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            _startMousePosition = e.GetPosition(this.colorSeq);
            _startPt = this.colorSeq.GetPositionFromPoint(_startMousePosition, true);
            AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(this.colorSeq);
            
            if (this._tbsAdorner != null)
            {
                adornerLayer.Remove(this._tbsAdorner);
            }
        }

        private void colorSeq_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(this.colorSeq);
            _cursorAdorner = new TextBlockSelectedAdorner(this.colorSeq, new Rect(_startMousePosition.X, 0.0, 0, 30));
            adornerLayer.Add(_cursorAdorner);
        }

...

    public class TextBlockSelectedAdorner : Adorner {
        // 被装饰的元素
        Rect _maskRect;
        
        // 基类初始化
        public TextBlockSelectedAdorner(UIElement element, Rect rect) : base(element) {
            this._maskRect = rect;
        }
        
        // 实现装饰器呈现的行为
        protected override void OnRender(DrawingContext drawingContext)
        {
            base.OnRender(drawingContext);
            Pen renderPen = new Pen(new SolidColorBrush(Colors.Red), 0);
            SolidColorBrush brush = new SolidColorBrush(Color.FromArgb(30,0,0,255));
            drawingContext.DrawRectangle(brush, renderPen, this._maskRect);
        }
    }