【问题标题】:Why Application.Selection.Range.Start returns incorrect value sometimes?为什么 Application.Selection.Range.Start 有时会返回不正确的值?
【发布时间】:2021-10-06 08:44:20
【问题描述】:

情境上下文 - MS Word 插件。
语言 - C#
问题:

我正在尝试获取当前光标位置。我正在使用Application.Selection.Range,因为它返回InsertionPoint。在每次按下Space,TabEnter 键后,我执行以下操作:MessageBox.Show(Application.Selection.Range.Start.ToString()); Sometimes 我看到 MessageBox 的值正确sometimes actual_value_of_insertion_point_position+128。为什么插入点索引有时会增加到 128?我没有做任何具体的事情,我只是输入一些文本,按空格键,有时会看到预期的正确值,有时却没有。

更新 实际上,我的问题更深——here我的另一个 SO 问题,详细描述。我的计划:

1) 当用户输入Space 时记住插入点 - 它返回下一个 未来字母的位置。
2) 如果用户输入了某个字母并且前一个键是空格,则表示用户首先输入一些新词的字母。创建如下Application.ActiveDocument.Range(remembered_pos,rem_pos+1) 的范围并根据需要设置样式。

我的代码

 private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
            {
                int pointerCode = Marshal.ReadInt32(lParam);
                string pressedKey = ((Keys)pointerCode).ToString();

                IntPtr curHandle = GetForegroundWindow();

                if(curHandle==wordHandle)
                {

                    //MessageBox.Show(app.ActiveDocument.Content.LanguageID +" "+ WdLanguageID.wdKazakh);
                    if(pressedKey.Equals("Space")||pressedKey.Equals("Return")||pressedKey.Equals("Tab"))
                    {

                        Word.Range r = app.Application.Selection.Range; 
                        MessageBox.Show(app.Application.Selection.Type.ToString());
                        MessageBox.Show("-"+r.Start.ToString()+"-"+r.End.ToString()); // sometimes +128!


                    }
                    else if(firstAfterSpace!=-1)
                    { // right now doesn't make sense 
                        MessageBox.Show(firstAfterSpace.ToString());
                        //Word.Range rng = app.Application.ActiveDocument.Range(firstAfterSpace,firstAfterSpace+1);
                        //MessageBox.Show("-"+rng.Text+"-");
                        //rng.Underline = Word.WdUnderline.wdUnderlineNone;
                        firstAfterSpace = -1;
                    }



                }

            }
            return CallNextHookEx(hookId, nCode, wParam, lParam);
        }

【问题讨论】:

  • 您的问题纯粹是信息性的吗?您是否只想知道为什么这是它的工作方式,或者您是否试图完成某件事而这会妨碍您?在后一种情况下 - 如果您能描述您希望完成的任务,将会很有帮助。
  • 当你有value + 128时,你也可以指出确切的情况,但不能只提到sometimes。如果您想在他/她自己的机器上检查此行为,这可能会有所帮助。
  • @Vadim,我想获取当前光标位置。我的意思是整数索引。我使用了Application.Selection.Range.Start,因为它返回插入点的索引——正是我需要的。它可以工作,但有时会返回不正确的值。我想知道如何解决这个问题。可能还有其他方法可以获取光标位置。
  • @KazJaw,测试用例描述:我输入了一些文本,按下了Space。光标位置的预期值为text.length+1。 MessageBox 显示text.length+1+128。当我越来越多地按 Space 时,有时我会看到预期值。
  • 我的评论意图是获取更多关于您的文档结构的信息,因为在按下 Space、Tab 和 Enter 时没有什么异常情况,它们在.Start 属性结果中出现了奇怪的结果。有桌子吗?领域?内容控件?等等如果你检查.End property- 它的行为是否也很奇怪?你能上传你的文件做一些测试吗?

标签: c# ms-word add-in


【解决方案1】:

您可以在有人按下Space, Return or Tab 后尝试不同的方式设置范围,假设您在任何这些“字符”之前搜索单词

这是您可以放入 If statement 的代码:

    Word.Range r = appWRD.Application.Selection.Range;
    Word.Range tmpR = r.Previous(Word.WdUnits.wdWord,2);
    MessageBox.Show("-" + tmpR.Start.ToString() + "-" + (r.Start-1).ToString());

    //set temporarily for checking word text
    tmpR = appWRD.ActiveDocument.Range(tmpR.Start, r.Start -1 );
    MessageBox.Show(string.Format("Word found: {0}!", tmpR.Text));
    //this shows it doesn't include any tab or space

提示。 Word 中有很多Range modification methods,但其中一些无法正常工作。根据我的测试,Previous 在这种情况下可以正常工作。

【讨论】:

  • 感谢您的调查。实际上,我需要记住的不是空格之前而是之后的范围。看到你在我的另一个问题上回答了 - 我知道如何更改某些范围的样式我不知道如何更改空格后第一个字母的样式。我接受了您的回答,因为 Previous 工作正常。不幸的是,我仍然无法从中获利(无论如何感谢您的回复,我接受了您的回答,因为您确实帮助我解决了128 shift 问题)此外,我尝试将 2 个答案结合起来 - 将光标位置与Previous 并简单地设置@ 987654329@ - 不起作用。我必须更深入)
  • 很高兴能够提供帮助。据我了解,这两个问题都是一个项目的一部分,因此我建议使用.Previous。我做了一些测试,上面的代码有助于在没有space 的情况下更改最后一个字。如果是这样,则下一个单词以默认样式书写。
  • 顺便说一句,您可能会自己找到它,但是... Previous method 第二个参数目前设置为 2。但是,根据我的测试,可能需要将 spaces 更改为 1 并将 2 保留为 Tabs and enters
  • @Baurzhan,我还在你的另一个问题中添加了另一个建议。
【解决方案2】:

我相信这是因为您使用的是全局挂钩事件。但我不知道原因。我刚刚试验过了。当我使用全局钩子时,范围的索引似乎增加了128。

【讨论】:

    【解决方案3】:

    当您从System.Windows.Forms.Timer 访问Selection.StartSelection.End 时,会观察到相同的行为。

    我认为原因是 Word 中文本缓冲区操作的优化。它不是插入一个字符,而是插入一个 128 个字符的块,但会推迟 Selection.Start 值的更新。

    但幸运的是,我们总能从selection.Previous(WdUnits.wdCharacter, 1).End 获得正确的Selection.Start 值。

    因此,获取正确选择开始和结束的代码如下所示:

    var selection = app.Selection.Range;
    
    var selStart = selection.Previous(WdUnits.wdCharacter, 1)?.End ?? 0;
    var selEnd = selStart + selection.End - selection.Start;
    

    【讨论】: