【问题标题】:How to set multiple links in RichEditBox without AccessViolationException如何在没有 AccessViolationException 的情况下在 RichEditBox 中设置多个链接
【发布时间】:2015-01-10 05:35:49
【问题描述】:

基本上我的问题是,如果用户编辑了内容,当我尝试以编程方式将超过 2 个链接应用到 ITextDocument 时,我会收到 AccessViolationException。我已经基于 windows phone (8.1) Blank App 模板制作了一个简单的演示应用程序。

我添加到主页:

<StackPanel Margin="19,0,0,0">
    <Button
        Content="Apply Links"
        Click="Button_Click"
        />
    <RichEditBox
        x:Name="RtfBox"
        Height="300"
        Loaded="RtfBox_Loaded"
        Margin="0,0,19,0"
        TextWrapping="Wrap"
        />
</StackPanel>

对于我添加的同一页面背后的代码(不包括使用语句):

    private void RtfBox_Loaded(object sender, RoutedEventArgs e)
    {
        //RtfBox.Document.SetText(TextSetOptions.None, "Links to demo, example, test. More links to demo, demo, example, test and test.");
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        var pages = new Dictionary<Guid, string> { { Guid.NewGuid(), "demo" }, { Guid.NewGuid(), "example" }, { Guid.NewGuid(), "test" } };

        // NOTE: Avoid performance implications of many small updates
        RtfBox.Document.BatchDisplayUpdates();

        ITextRange range;
        foreach (var page in pages)
        {
            var link = string.Format("\"richtea.demo://pages/{0}\"", page.Key);
            var skip = 0;

            while ((range = RtfBox.Document.GetRange(skip, TextConstants.MaxUnitCount)).FindText(page.Value, TextConstants.MaxUnitCount, FindOptions.None) != 0)
            {
                if (range.Link == "")
                {
                    // TODO: Stop this throw exceptions
                    System.Diagnostics.Debug.WriteLine("Setting text at position {0} to link: '{1}'.", range.StartPosition, link);
                    range.Link = link;
                }

                skip = range.EndPosition;
            }
        }

        RtfBox.Document.ApplyDisplayUpdates();
    }

如果您启动它并输入“演示页面的链接”之类的内容并单击按钮,它就会正确地变成一个链接。您可以继续输入相同的文本并单击按钮,它会继续工作。

但是,如果您输入三个或更多(出于某种原因对我来说总是 3 个或更多)demoexampletest em>(我的关键字)并点击按钮,它在设置range.Link = link 时出现AccessViolationException 错误。值得注意的是,如果您在调试时检查,range.Link 属性实际上已设置。

更有趣的是,如果您取消注释RtfBox_Loaded 的内容,然后运行应用程序并立即单击按钮,它会处理得很好。所以它似乎与在 RichEditBox 上设置的选择有关?我尝试在应用链接之前禁用控件,但这对我没有帮助。

其他一些让我更难在此处诊断问题的因素包括:

  • 如果我逐行调试,它似乎工作得更频繁,所以也可能与时间有关
  • 我似乎无法在 UI 线程上使用 ITextDocument(COM 对象无法转换),因此虽然异步似乎是更好的方法,但我在这里没有成功。

另外,为了记录,我尝试批量进行所有更新而不是用户键入它们的原因是我不想在重命名或删除笔记时处理清理,我真的不想在编辑时加入或保存这些链接,但我可以忍受以后。

【问题讨论】:

标签: windows-phone-8.1 richeditbox


【解决方案1】:

这个解决方案是posted on the MSDN forums Eric Fleck 为我工作的:

RtfBox.Document.Selection.StartPosition = RtfBox.Document.Selection.EndPosition = range.StartPosition;
range.Link = link;
RtfBox.Document.Selection.StartPosition = RtfBox.Document.Selection.EndPosition = range.EndPosition;

似乎围绕正在设置的每个链接执行此操作很重要,因为除非我非常错误,否则我在更新所有链接之前尝试过此操作,但没有帮助。

我还没有使用将选择恢复到其原始位置的功能,但我将来可能想要这样做,所以我制作了这个小实用程序类。另外,我可以将这些地方包装在 using() 块中以获得一些语法糖。

public static class ITextDocumentExtensions
{
    public static IDisposable SuppressSelection(this ITextDocument document)
    {
        var start = document.Selection.StartPosition;
        var end = document.Selection.EndPosition;

        var disposable = new ActionDisposable(() => document.Selection.SetRange(start, end));
        document.Selection.SetRange(0, 0);

        return disposable;
    }

    private sealed class ActionDisposable : IDisposable
    {
        private readonly Action dispose;

        public ActionDisposable(Action dispose)
        {
            this.dispose = dispose;
        }

        public void Dispose()
        {
            dispose();
        }
    }
}

这让我可以写作

using (RtfBox.Document.SuppressSelection())
{
    range.Link = link;
}

【讨论】:

    猜你喜欢
    • 2018-04-15
    • 1970-01-01
    • 2015-07-17
    • 2012-10-05
    • 1970-01-01
    • 2020-01-12
    • 2012-04-14
    • 2018-03-24
    • 2012-06-24
    相关资源
    最近更新 更多