代码之家  ›  专栏  ›  技术社区  ›  user5856424

RichTextBox用表情符号/图像替换字符串

  •  5
  • user5856424  · 技术社区  · 8 年前

    :D )带有表情符号图像。 到目前为止,我已经可以使用它了,除了当我在现有单词/字符串之间编写表情符号字符串时,图像会插入到行的末尾。

    hello (inserting :D here) this is a message
    结果: hello this is a message ☺ <&书信电报;形象

    public class Emoticon
    {
        public Emoticon(string key, Bitmap bitmap)
        {
            Key = key;
            Bitmap = bitmap;
            BitmapImage = bitmap.ToBitmapImage();
        }
    
        public string Key { get; }
        public Bitmap Bitmap { get; }
        public BitmapImage BitmapImage { get; }
    }
    
    public class EmoticonRichTextBox : RichTextBox
    {
        private readonly List<Emoticon> _emoticons;
    
        public EmoticonRichTextBox()
        {
            _emoticons = new List<Emoticon>
            {
                new Emoticon(":D", Properties.Resources.grinning_face)
            };
        }
    
        protected override void OnTextChanged(TextChangedEventArgs e)
        {
            base.OnTextChanged(e);
            Dispatcher.InvokeAsync(Look);
        }
    
        private void Look()
        {
            const string keyword = ":D";
    
            var text = new TextRange(Document.ContentStart, Document.ContentEnd);
            var current = text.Start.GetInsertionPosition(LogicalDirection.Forward);
    
            while (current != null)
            {
                var textInRun = current.GetTextInRun(LogicalDirection.Forward);
                if (!string.IsNullOrWhiteSpace(textInRun))
                {
                    var index = textInRun.IndexOf(keyword, StringComparison.Ordinal);
                    if (index != -1)
                    {
                        var selectionStart = current.GetPositionAtOffset(index, LogicalDirection.Forward);
                        if (selectionStart == null)
                            continue;
    
                        var selectionEnd = selectionStart.GetPositionAtOffset(keyword.Length, LogicalDirection.Forward);
                        var selection = new TextRange(selectionStart, selectionEnd) { Text = string.Empty };
    
                        var emoticon = _emoticons.FirstOrDefault(x => x.Key.Equals(keyword));
                        if (emoticon == null)
                            continue;
    
                        var image = new System.Windows.Controls.Image
                        {
                            Source = emoticon.BitmapImage,
                            Height = 18,
                            Width = 18,
                            Margin = new Thickness(0, 3, 0, 0)
                        };
    
                        // inserts at the end of the line
                        selection.Start?.Paragraph?.Inlines.Add(image);
    
                        // doesn't work
                        CaretPosition = CaretPosition.GetPositionAtOffset(1, LogicalDirection.Forward);
                    }
                }
    
                current = current.GetNextContextPosition(LogicalDirection.Forward);
            }
        }
    }
    
    public static class BitmapExtensions
    {
        public static BitmapImage ToBitmapImage(this Bitmap bitmap)
        {
            using (var stream = new MemoryStream())
            {
                bitmap.Save(stream, ImageFormat.Png);
                stream.Position = 0;
    
                var image = new BitmapImage();
                image.BeginInit();
                image.CacheOption = BitmapCacheOption.OnLoad;
                image.DecodePixelHeight = 18;
                image.DecodePixelWidth = 18;
                image.StreamSource = stream;
                image.EndInit();
                image.Freeze();
    
                return image;
            }
        }
    }
    
    2 回复  |  直到 8 年前
        1
  •  2
  •   Yusuf Tarık Günaydın M2012    8 年前

    selection.Start?.Paragraph?.Inlines.Add(image); 。将图像附加到段落末尾。您应该使用 InsertBefore InsertAfter 方法。

    但要使用这些方法,您应该迭代内联,并找到适当的内联,以便在之前或之后插入。这并不难。您可以通过比较来确定内联 selectionStart selectionEnd ElementStart ElementEnd

    另一个棘手的可能性是,要插入的位置可能位于内联。然后,您应该拆分该内联并创建其他三个:

    • 在插入位置之前包含元素的元素
    • 一个包含图像的
    • 插入位置后包含元素的一个。

    Wpf的RichTextBox没有最漂亮的API。有时很难相处。还有另一个控件称为 AvalonEdit

        2
  •  1
  •   user5856424 user5856424    8 年前

    @Yusuf Tarık Günaydın 建议,我寻找 AvalonEdit 控制,使这个技巧相当容易。

    example 我只需要创建一个 VisualLineElementGenerator 它查找表情匹配并插入图像。

    public static class BitmapExtensions
    {
        public static BitmapImage ToBitmapImage(this Bitmap bitmap)
        {
            using (var stream = new MemoryStream())
            {
                bitmap.Save(stream, ImageFormat.Png);
                stream.Position = 0;
    
                var image = new BitmapImage();
                image.BeginInit();
                image.CacheOption = BitmapCacheOption.OnLoad;
                image.DecodePixelHeight = 18;
                image.DecodePixelWidth = 18;
                image.StreamSource = stream;
                image.EndInit();
                image.Freeze();
    
                return image;
            }
        }
    }
    
    public class Emoticon
    {
        public Emoticon(string key, Bitmap bitmap)
        {
            Key = key;
            Bitmap = bitmap;
            BitmapImage = bitmap.ToBitmapImage();
        }
    
        public string Key { get; }
        public Bitmap Bitmap { get; }
        public BitmapImage BitmapImage { get; }
    }
    
    public class EmoticonTextBox : TextEditor
    {
        public EmoticonTextBox()
        {
            HorizontalScrollBarVisibility = ScrollBarVisibility.Auto;
            VerticalScrollBarVisibility = ScrollBarVisibility.Disabled;
    
            TextArea.TextView.ElementGenerators.Add(new ImageElementGenerator());
        }
    }
    
    public class ImageElementGenerator : VisualLineElementGenerator
    {
        // To use this class:
        // textEditor.TextArea.TextView.ElementGenerators.Add(new ImageElementGenerator());
    
        private static readonly Regex ImageRegex = new Regex(@":D", RegexOptions.IgnoreCase);
    
        private readonly List<Emoticon> _emoticons;
    
        public ImageElementGenerator()
        {
            _emoticons = new List<Emoticon>
            {
                new Emoticon(":D", Properties.Resources.grinning_face)
            };
        }
    
        private Match FindMatch(int startOffset)
        {
            var endOffset = CurrentContext.VisualLine.LastDocumentLine.EndOffset;
            var relevantText = CurrentContext.Document.GetText(startOffset, endOffset - startOffset);
    
            return ImageRegex.Match(relevantText);
        }
    
        public override int GetFirstInterestedOffset(int startOffset)
        {
            var match = FindMatch(startOffset);
            return match.Success ? startOffset + match.Index : -1;
        }
    
        public override VisualLineElement ConstructElement(int offset)
        {
            var match = FindMatch(offset);
            if (!match.Success || match.Index != 0)
                return null;
    
            var key = match.Groups[0].Value;
            var emoticon = _emoticons.FirstOrDefault(x => x.Key.Equals(key));
    
            var bitmap = emoticon?.BitmapImage;
            if (bitmap == null)
                return null;
    
            var image = new System.Windows.Controls.Image
            {
                Source = bitmap,
                Width = bitmap.PixelWidth,
                Height = bitmap.PixelHeight
            };
    
            return new InlineObjectElement(match.Length, image);
        }
    }
    
    推荐文章