如何使用RichTextBox删除烦人的BEEP

时间:2011-01-13 18:20:29

标签: c# winforms richtextbox

我在新表单上放置了一个RichTextBox控件并启动了该项目。所以RichTextBox.Text =“”;

每次按下向上或向下键,我都会听到恼人的BEEP声音!如何摆脱这个问题?

在KeyDown方法中使用“e.SuppressKeyPress = true”会锁定Cursor位置。

5 个答案:

答案 0 :(得分:1)

好吧,只有当插入符号位于第一行并且键处于启用状态时,或者在最后一行并且键处于关闭位置或位置0且键保持等等时,您可以尝试禁止键。

也就是说,这就是大多数文本框的行为方式,并且声音是在操作系统首选项中设置的。如果你试图将插入符号移到文本框的限制之外,你会在Wordpad或Outlook中得到同样的哔哔声。

答案 1 :(得分:1)

首先,我们需要向丰富的编辑窗口发送EM_GETOLEINTERFACE消息-这是检索IRichEditOle对象,客户端可以使用该对象来访问丰富的编辑控件的组件对象模型(COM)功能。

然后要获取ITextServices指针,请对EM_GETOLEINTERFACE返回的专用QueryInterface指针调用IUnknown

这里存在一个有趣的地方-IID_ITextServices鲜为人知,但需要从 Msftedit.dll

进入运行时。

来自About Windowless Rich Edit Controls

  

Msftedit.dll 会导出名为 IID_ITextServices 的接口标识符(IID),您可以使用该接口标识符查询IUnknown指针以获取 ITextServices 接口。

在获得ITextServices指针之后-我们只需调用OnTxPropertyBitsChange(TXTBIT_ALLOWBEEP, 0)

代码示例:

    if (HMODULE hmodRichEdit = LoadLibrary(L"Msftedit.dll"))
    {
        // create richedit window
        if (HWND hwndRich = CreateWindowExW(0, MSFTEDIT_CLASS, ...))
        {
            if (IID* pIID_ITS = (IID*) GetProcAddress(hmodRichEdit, "IID_ITextServices"))
            {
                IUnknown* pUnk;
                if (SendMessageW(hwndRich, EM_GETOLEINTERFACE, 0, (LPARAM)&pUnk))
                {
                    ITextServices* pTxtSrv;
                    HRESULT hr = pUnk->QueryInterface(*pIID_ITS, (void**)&pTxtSrv);
                    pUnk->Release();
                    if (0 <= hr)
                    {
                        pTxtSrv->OnTxPropertyBitsChange(TXTBIT_ALLOWBEEP, 0);
                        pTxtSrv->Release();
                    }
                }
            }
        }
    }

答案 2 :(得分:1)

以下是使用@RbMm's answer中所述的ITextServices接口方法的.Net实现。如果您觉得这有用,请考虑提高答案。

此实现公开了Winform RichTextBox的两个扩展方法(EnableBeepDisableBeep)。同时提供了C#和Vb.Net版本。

由于我们只对使用ITextServices接口中定义的OnTxPropertyBitsChange函数感兴趣,因此使用该接口的简化实现,类似于将“嵌入互操作类型”用作COM引用时所创建的实现。如果已安装Windows SDK,则应在类似于“ C:\ Program Files(x86)\ Windows Kits \ 10 \ Include \ 10.0.18362.0 \ um \ TextServ.h”的路径下找到“ TextServ.h”文件。 。该文件定义了完整的ITextServices类接口。

C#版本

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
//----
public static class RTBBeepExtensions
{
    public static void EnableBeep(this RichTextBox rtb)
    {
        SetBeepInternal(rtb, true);
    }

    public static void DisableBeep(this RichTextBox rtb)
    {
        SetBeepInternal(rtb, false);
    }

    private static void SetBeepInternal(RichTextBox rtb, bool beepOn)
    {
        const Int32 WM_USER = 0x400;
        const Int32 EM_GETOLEINTERFACE = WM_USER + 60;
        const Int32 COMFalse = 0;
        const Int32 COMTrue = ~COMFalse; // -1

        ITextServices textServices = null;
        // retrieve the rtb's OLEINTERFACE using the Interop Marshaller to cast it as an ITextServices
        // 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.
        SendMessage(new HandleRef(rtb, rtb.Handle), EM_GETOLEINTERFACE, IntPtr.Zero, ref textServices);
        textServices.OnTxPropertyBitsChange(TXTBIT.ALLOWBEEP, beepOn ? COMTrue : COMFalse));
        Marshal.ReleaseComObject(textServices);
    }

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

    #region ITextServices // From TextServ.h
    [ComImport(), Guid("8d33f740-cf58-11ce-a89d-00aa006cadc5"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    private interface ITextServices
    {
        //see: Slots in the V-table
        //     https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/metadata/imetadataemit-definemethod-method#slots-in-the-v-table
        void _VtblGap1_16();
        Int32 OnTxPropertyBitsChange(TXTBIT dwMask, Int32 dwBits);
    }

    private enum TXTBIT : uint
    {
        /// <summary>If TRUE, beeping is enabled.</summary>
        ALLOWBEEP = 0x800
    }
    #endregion

}

VB.Net版本

Imports System
Imports System.Runtime.InteropServices
Imports System.Runtime.CompilerServices
Imports System.Windows.Forms
' -------
Public Module RTBBeepExtensions
  <Extension()>
  Public Sub EnableBeep(rtb As RichTextBox)
    SetBeepInternal(rtb, True)
  End Sub

  <Extension()>
  Public Sub DisableBeep(rtb As RichTextBox)
    SetBeepInternal(rtb, False)
  End Sub

  Private Sub SetBeepInternal(rtb As RichTextBox, beepOn As Boolean)
    Const WM_USER As Int32 = &H400
    Const EM_GETOLEINTERFACE As Int32 = WM_USER + 60
    Const COMFalse As Int32 = 0
    Const COMTrue As Int32 = Not COMFalse ' -1

    Dim textServices As ITextServices = Nothing
    ' retrieve the rtb's OLEINTERFACE using the Interop Marshaller to cast it as an ITextServices
    ' 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.
    SendMessage(New HandleRef(rtb, rtb.Handle), EM_GETOLEINTERFACE, IntPtr.Zero, textServices)
    textServices.OnTxPropertyBitsChange(TXTBIT.ALLOWBEEP, If(beepOn, COMTrue, COMFalse))
    Marshal.ReleaseComObject(textServices)
  End Sub

  <DllImport("user32.dll", CharSet:=CharSet.Auto)>
  Private Function SendMessage(ByVal hWnd As HandleRef, ByVal msg As Int32, ByVal wParam As IntPtr, ByRef lParam As ITextServices) As IntPtr
  End Function

#Region "ITextServices" ' From TextServ.h
  <ComImport(), Guid("8d33f740-cf58-11ce-a89d-00aa006cadc5"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
  Private Interface ITextServices
    'see: Slots in the V-table
    '     https://docs.microsoft.com/en-us/dotnet/framework/unmanaged-api/metadata/imetadataemit-definemethod-method#slots-in-the-v-table
    Sub _VtblGap1_16()
    Function OnTxPropertyBitsChange(ByVal dwMask As TXTBIT, ByVal dwBits As Int32) As Int32
  End Interface

  Private Enum TXTBIT As UInt32
    ''' <summary>If TRUE, beeping is enabled.</summary>
    ALLOWBEEP = &H800
  End Enum
#End Region

End Module

如果您不熟悉扩展方法,请参考以下文档链接。

Extension Methods (C# Programming Guide)

Extension Methods (Visual Basic)

答案 3 :(得分:0)

下面的代码应该停止哔哔声,并使用包装和解包的文本:

private void richTextBox1_KeyDown(object sender, KeyEventArgs e)
{
    if (
        richTextBox1.GetLineFromCharIndex(richTextBox1.SelectionStart) == 0 && e.KeyData == Keys.Up ||
        richTextBox1.GetLineFromCharIndex(richTextBox1.SelectionStart) == richTextBox1.GetLineFromCharIndex(richTextBox1.TextLength) && e.KeyData == Keys.Down ||
        richTextBox1.SelectionStart == richTextBox1.TextLength && e.KeyData == Keys.Right ||
        richTextBox1.SelectionStart == 0 && e.KeyData == Keys.Left
    ) e.Handled = true;
}

答案 4 :(得分:-3)

不要将光标移动到富文本框的边界之外。 “当我这样做时,医生会疼吗......”