c# - RichTextBox 用表情/图片替换字符串

标签 c# wpf richtextbox emoticons

在 RichtTextBox 中,我想用表情符号图像自动替换表情符号字符串(例如 :D)。 到目前为止我已经开始工作了,除了当我在现有的单词/字符串之间写表情符号字符串时,图像被插入到行的末尾。

例如: 你好(在这里插入 :D)这是一条消息
结果是: 你好,这是一条消息 ☺ << 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 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;
        }
    }
}

最佳答案

错误行是 selection.Start?.Paragraph?.Inlines.Add(image);。您将图像附加到段落的末尾。您应该使用 InsertBeforeInsertAfter 方法之一。

但要使用这些方法,您应该遍历内联并找到合适的内联插入之前或之后。这并不难。您可以通过将 selectionStartselectionEnd 与内联的 ElementStartElementEnd 属性进行比较来确定内联。

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

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

然后,您可以删除内联并在适当的位置插入新的三个内联。

Wpf 的 RichTextBox 没有最漂亮的 API。有时很难与之合作。还有另一个控件称为 AvalonEdit .它比 RichTextBox 更容易使用。您可能需要考虑一下。

关于c# - RichTextBox 用表情/图片替换字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45500571/

相关文章:

wpf - Prism:创建外壳后将模块加载到目录中

c# - 如何以不同的颜色显示文本

C# - 动态更改 RichTextBox 中的文本字体?

c# - 依赖注入(inject)问题——如何清理我的实现?

c# - CaSTLe Windsor 注册的类型不同于类型发现中使用的类型

wpf - FlowDocument 中的波浪下划线

c# - 如何将动态DoubleAnimation设置为To或From值

c# - 无法将类型 'System.Collections.Generic.List<>' 隐式转换为 'System.Threading.Tasks.Task<>>

c# - 是否可以将 Resharper Intellisense 配置为按字母顺序排序?

WPF。如何将 InlineUIContainer 内容中的文本与 RichTextBox 中的外部文本对齐