Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/285.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何将RichTextBox控件滚动到给定点,而不考虑插入符号的位置_C#_Winforms_Richtextbox - Fatal编程技术网

C# 如何将RichTextBox控件滚动到给定点,而不考虑插入符号的位置

C# 如何将RichTextBox控件滚动到给定点,而不考虑插入符号的位置,c#,winforms,richtextbox,C#,Winforms,Richtextbox,在我的WinForms应用程序中,我有一个包含长文本的RichTextBox控件。我需要通过编程将其滚动到以字符索引表示的给定点,而不管选择插入符号位于何处。我需要这样一种方法: //scroll the control so that the 3512th character is visible. rtf.ScrollToPosition(3512); 我发现的所有类似问题的答案都使用ScrollToCaret方法,如果您想滚动到插入符号位置,这是很好的。但是我需要滚动到不同的位置,而不是

在我的WinForms应用程序中,我有一个包含长文本的RichTextBox控件。我需要通过编程将其滚动到以字符索引表示的给定点,而不管选择插入符号位于何处。我需要这样一种方法:

//scroll the control so that the 3512th character is visible.
rtf.ScrollToPosition(3512);
我发现的所有类似问题的答案都使用ScrollToCaret方法,如果您想滚动到插入符号位置,这是很好的。但是我需要滚动到不同的位置,而不是插入符号,并且不改变插入符号的位置。我该怎么做


谢谢。

您可以使用中实现的相同方法来完成此任务。此方法基于使用底层RichEdit控件实现的基于COM的方法

下面定义了扩展方法ScrollToCharPosition。它使用和接口的缩写定义

public static class RTBExtensions
{

    public static void ScrollToCharPosition(this RichTextBox rtb, Int32 charPosition)
    {
        const Int32 WM_USER = 0x400;
        const Int32 EM_GETOLEINTERFACE = WM_USER + 60;
        const Int32 tomStart = 32;

        if (charPosition < 0 || charPosition > rtb.TextLength - 1)
        {
            throw new ArgumentOutOfRangeException(nameof(charPosition), $"{nameof(charPosition)} must be in the range of 0 to {rtb.TextLength - 1}.");
        }

        // retrieve the rtb's OLEINTERFACE and use the Interop Marshaller to cast it as an ITextDocument
        // The control calls the AddRef method for the object before returning, so the calling application must call the Release method when it is done with the object.
        ITextDocument doc = null;
        SendMessage(new HandleRef(rtb, rtb.Handle), EM_GETOLEINTERFACE, IntPtr.Zero, ref doc);
        ITextRange rng = null;
        if (doc != null)
        {
            try
            {
                rng = (RTBExtensions.ITextRange)doc.Range(charPosition, charPosition);
                rng.ScrollIntoView(tomStart);
            }
            finally
            {
                if (rng != null)
                {
                    Marshal.ReleaseComObject(rng);
                }
                Marshal.ReleaseComObject(doc);
            }
        }
    }

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    private extern static IntPtr SendMessage(HandleRef hWnd, Int32 msg, IntPtr wParam, ref ITextDocument lParam);

    [ComImport, Guid("8CC497C0-A1DF-11CE-8098-00AA0047BE5D")]
    private interface ITextDocument
    {
        [MethodImpl((short)0, MethodCodeType = MethodCodeType.Runtime)]
        void _VtblGap1_17();
        [return: MarshalAs(UnmanagedType.Interface)]
        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(15)]
        ITextRange Range([In] int cp1, [In] int cp2);
    }

    [ComImport, Guid("8CC497C2-A1DF-11CE-8098-00AA0047BE5D")]
    private interface ITextRange
    {
        [MethodImpl((short)0, MethodCodeType = MethodCodeType.Runtime)]
        void _VtblGap1_49();
        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(0x242)]
        void ScrollIntoView([In] int Value);
    }
}

用法示例:richtextbox1.ScrollToCharPosition50

您可以使用中实现的相同方法来完成此操作。此方法基于使用底层RichEdit控件实现的基于COM的方法

下面定义了扩展方法ScrollToCharPosition。它使用和接口的缩写定义

public static class RTBExtensions
{

    public static void ScrollToCharPosition(this RichTextBox rtb, Int32 charPosition)
    {
        const Int32 WM_USER = 0x400;
        const Int32 EM_GETOLEINTERFACE = WM_USER + 60;
        const Int32 tomStart = 32;

        if (charPosition < 0 || charPosition > rtb.TextLength - 1)
        {
            throw new ArgumentOutOfRangeException(nameof(charPosition), $"{nameof(charPosition)} must be in the range of 0 to {rtb.TextLength - 1}.");
        }

        // retrieve the rtb's OLEINTERFACE and use the Interop Marshaller to cast it as an ITextDocument
        // The control calls the AddRef method for the object before returning, so the calling application must call the Release method when it is done with the object.
        ITextDocument doc = null;
        SendMessage(new HandleRef(rtb, rtb.Handle), EM_GETOLEINTERFACE, IntPtr.Zero, ref doc);
        ITextRange rng = null;
        if (doc != null)
        {
            try
            {
                rng = (RTBExtensions.ITextRange)doc.Range(charPosition, charPosition);
                rng.ScrollIntoView(tomStart);
            }
            finally
            {
                if (rng != null)
                {
                    Marshal.ReleaseComObject(rng);
                }
                Marshal.ReleaseComObject(doc);
            }
        }
    }

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    private extern static IntPtr SendMessage(HandleRef hWnd, Int32 msg, IntPtr wParam, ref ITextDocument lParam);

    [ComImport, Guid("8CC497C0-A1DF-11CE-8098-00AA0047BE5D")]
    private interface ITextDocument
    {
        [MethodImpl((short)0, MethodCodeType = MethodCodeType.Runtime)]
        void _VtblGap1_17();
        [return: MarshalAs(UnmanagedType.Interface)]
        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(15)]
        ITextRange Range([In] int cp1, [In] int cp2);
    }

    [ComImport, Guid("8CC497C2-A1DF-11CE-8098-00AA0047BE5D")]
    private interface ITextRange
    {
        [MethodImpl((short)0, MethodCodeType = MethodCodeType.Runtime)]
        void _VtblGap1_49();
        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime), DispId(0x242)]
        void ScrollIntoView([In] int Value);
    }
}
用法示例:richtextbox1.ScrollToCharPosition50

您可以使用它向RichEdit控件发送消息,在wParam的低位指定SB_拇指位置,在HIWORD中指定滚动到的绝对垂直位置

该方法属于,因此适用于TextBox类,太返回显示特定位置字符的相对物理位置。如果字符位置高于当前滚动位置,则该值可能为负值,如果字符位置低于当前滚动位置,则为当前滚动位置与字符位置之间的差值,除非当前滚动位置为0

假设您的RichTextBox名为richTextBox1:

使用,例如,确定单词或短语的位置;匹配图案的位置由匹配的Index属性返回。 使用GetPositionFromCharIndex0检查当前偏移量 将当前垂直位置定义的偏移量的绝对值添加到GetPositionFromCharIndexmatchPos返回的值(以像素表示),其中matchPos是要滚动到的字符/字/图案的位置。 使用计算的位置调用SendMessage,并指定将拇指移动到此位置,并将SB_THUMBPOSITION作为wParam的一部分传递到该位置。 您可以使用向RichEdit控件发送消息,在wParam的低位中指定SB_THUMBPOSITION,并在HIWORD中指定要滚动到的绝对垂直位置

该方法属于,因此适用于TextBox类,太返回显示特定位置字符的相对物理位置。如果字符位置高于当前滚动位置,则该值可能为负值,如果字符位置低于当前滚动位置,则为当前滚动位置与字符位置之间的差值,除非当前滚动位置为0

假设您的RichTextBox名为richTextBox1:

使用,例如,确定单词或短语的位置;匹配图案的位置由匹配的Index属性返回。 使用GetPositionFromCharIndex0检查当前偏移量 将当前垂直位置定义的偏移量的绝对值添加到GetPositionFromCharIndexmatchPos返回的值(以像素表示),其中matchPos是要滚动到的字符/字/图案的位置。 使用计算的位置调用SendMessage,并指定将拇指移动到此位置,并将SB_THUMBPOSITION作为wParam的一部分传递到该位置。
您是否尝试过此int s=rtb.SelectionStart;rtb.SuspendLayout;rtb.SelectionStart=12334;rtb.ScrollToCaret;rtb.SelectionStart=s;rtb.1布局;这回答了你的问题吗@奥利维耶罗吉尔:那可能有用。谢谢。您尝试过这个int s=rtb.SelectionStart;rtb.SuspendLayout;rtb.SelectionStart=12334;rtb.ScrollToCaret;rtb.SelectionStart=s;rtb.1布局;这回答了你的问题吗@奥利维耶罗吉尔:那可能有用。谢谢,谢谢。我将首先尝试评论中建议的方法,因为它们看起来更简单。如果它们不起作用,我将尝试您的方法。@CESARGE,如果您正在尝试建议的WM_VSCROLL/GetPositionFromCharIndex,请注意这些仅限于使用16位坐标值。根据字体高度,在几千行之后,您将遇到问题。这对于您的使用可能不是一个问题,但您应该意识到其局限性。还要认识到GetPositionFromCharIndex可以返回负值,因此您也需要考虑到这一点。祝你好运,谢谢。我将首先尝试评论中建议的方法,因为它们看起来更简单。如果它们不起作用,我将尝试您的方法。@Cesarg,如果您正在尝试建议的WM_VSCROLL/GetPositionFromCharIndex,请注意 软管仅限于使用16位坐标值。根据字体高度,在几千行之后,您将遇到问题。这对于您的使用可能不是一个问题,但您应该意识到其局限性。还要认识到GetPositionFromCharIndex可以返回负值,因此您也需要考虑到这一点。祝你好运
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
internal static extern int SendMessage(IntPtr hWnd, uint uMsg, int wParam, int lParam);

private const uint WM_VSCROLL = 0x0115;
private const int SB_THUMBPOSITION = 4;