• WPF RichTextBox 当前光标后一个字符是文档的第几个字符


    WPF RichTextBox 当前光标后一个字符是文档的第几个字符

    运行环境:Win10 x64, NetFrameWork 4.8, 作者:乌龙哈里,日期:2019-05-05


    参考:

    章节:

    1. 挑选显示数据容器历程
    2. 读取文本到 RichTextBox
    3. 计算第几个字符

    一、挑选显示数据容器历程

    最近想写一个类似 UltraEdit 查看文件内容,以16进制显示每字节。首先碰到的问题就是下面这个界面:


    在 WPF 下尝试了不少方法,同时读一个28k byte 的文件,利弊如下:

    方法一:用 Canvas 做容器,一个字节一个 Textbox,写入、修改、变色等操作是很方便,结果载入数据显示的时候要停顿10多秒,而且内存占用达到了1g 以上,同样的文件 UltraEdit 才占用 28m 左右。放弃;

    方法二:把 TextBox 换成轻量些的 TextBlock,内存占用达 120m左右,载入数据也比较慢,放弃;

    方法三:还用 TextBox ,但是只用显示页面上能摆放的数量,不再一个字节一个,占用才60多兆,但用鼠标滚动翻页时,停顿感很强,不流畅。放弃;

    方法三:用 一个字节一个 GlyphRun 直接在 Canvas上画出来,内存占用也很大,比方法二还要大,不明所以,放弃;

    方法四:用 一个字节一个 FormattedText 画在 Canvas 上,直接在 Canvas 的 OnRender() 里生成也占用内存 80多兆。不在 OnRender() 里需要把 FormattedText 转化成 FrameworkElement,占用直接上到120多兆。放弃

    最后发现用 一个 RichTextBox 来载入数据又快又省,占用内存才28m,和 UltraEdit 相当。(不用单个 TextBox 是因为改动时想标记不同颜色,TextBox 很难做到)。
    以后把这些实验的心得也记录下来。

    二、读取文本到 RichTextBox

    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < CntData.Length; i++)//CntData是读取文件的字节数组
    {
        if (i % NumInLine == 0 && i != 0) //NumInLine=16 每行显示16个字节
        {
            sb.Append("
    ");
        }
        sb.Append(CntData[i].ToString("X2"));
        sb.Append(" ");
    }
    //--TextRange.Text=sb.ToString()方法比下面用 Paragraph 的要慢好多
    //TextRange tr = new TextRange(rtbShow.Document.ContentStart, rtbShow.Document.ContentEnd);
    //tr.Text = sb.ToString();
    Paragraph p = new Paragraph();
    p.Inlines.Add(new Run(sb.ToString()));
    rtbShow.Document.Blocks.Add(p);//rtbShow RichTextBox 控件的名称
    InputMethod.SetIsInputMethodEnabled(rtbShow, false);//关掉输入法
    //把输入改成 overwrite 模式
    PropertyInfo textEditorProperty = typeof(RichTextBox).GetProperty("TextEditor", BindingFlags.NonPublic | BindingFlags.Instance);
    object textEditor = textEditorProperty.GetValue(rtbShow, null);
    // set _OvertypeMode on the TextEditor
    PropertyInfo overtypeModeProperty = textEditor.GetType().GetProperty("_OvertypeMode", BindingFlags.NonPublic | BindingFlags.Instance);
    overtypeModeProperty.SetValue(textEditor, true, null);
    
    

    三、计算第几个字符

    //---计算当前鼠标后一个字符从文档开始字符起算是第几个字符
    private int GetCharOffset(RichTextBox rtb)
    {
        TextPointer start = rtb.CaretPosition;//当前鼠标位置
         int n = 0;
        TextPointerContext tpc = start.GetPointerContext(LogicalDirection.Backward);
        while (tpc!=TextPointerContext.None)
        {
            if (tpc == TextPointerContext.Text) n++;
            start = start.GetPositionAtOffset(-1, LogicalDirection.Backward);//注意是 -1
            tpc = start.GetPointerContext(LogicalDirection.Backward);
        }
        return n-1;//从0起算
    }
    
    

    看了 MS 关于 GetPositionAtOffset() 的解释:
    参数
    offset
    Int32
    偏移量(以符号数为单位),使用它计算并返回位置。 如果偏移量为负,则返回的 TextPointer 位于当前 TextPointer 之前;否则,位于它之后。
    direction
    LogicalDirection
    LogicalDirection 值之一,它指定返回的 TextPointer 的逻辑方向。

    上面那段程序中只能写-1,要是是 1的话,永远得不到 TextPointerContext.None 。

  • 相关阅读:
    在javascript中如何取消事件冒泡
    ThinkPHP与EasyUI整合之二(datagrid):删除多条记录
    Jquery动画效果地铁站名指示等效果
    ubuntu 10.4 setup vm tools log
    Windows下Critical Section、Event、Mutex、Semaphores区别
    联通GPRS卡在windows mobile操作系统手机上网如何设置
    hope DATA
    电动车电池正确的使用方法
    C语言运算符表
    深圳市职业技能鉴定报名
  • 原文地址:https://www.cnblogs.com/leemano/p/10810746.html
Copyright © 2020-2023  润新知