Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/330.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# 在Winforms RichTextBox控件中,如何使最后一行链接下方的空间不可单击?_C#_Winforms_Hyperlink_Richtextbox - Fatal编程技术网

C# 在Winforms RichTextBox控件中,如何使最后一行链接下方的空间不可单击?

C# 在Winforms RichTextBox控件中,如何使最后一行链接下方的空间不可单击?,c#,winforms,hyperlink,richtextbox,C#,Winforms,Hyperlink,Richtextbox,在Windows forms C#应用程序中,我有许多RichTextBox控件,它们将链接显示为文本框的最后一行,之后没有换行符 问题在于,链接下方的所有空白区域都是可点击的链接。我知道文本下方的空白通常是windows中该行的“一部分”——例如,将光标放在这篇文章的正下方,然后单击并拖动——您将选择最后一行。但一般来说,这不包括可点击的链接。用这篇文章的标题试试看——你可以选择标题,但是你的光标不是可点击的“手”,直到你真正直接在标题上 我可以通过将数据更改为始终包含尾随换行符来解决这个问题

在Windows forms C#应用程序中,我有许多RichTextBox控件,它们将链接显示为文本框的最后一行,之后没有换行符

问题在于,链接下方的所有空白区域都是可点击的链接。我知道文本下方的空白通常是windows中该行的“一部分”——例如,将光标放在这篇文章的正下方,然后单击并拖动——您将选择最后一行。但一般来说,这不包括可点击的链接。用这篇文章的标题试试看——你可以选择标题,但是你的光标不是可点击的“手”,直到你真正直接在标题上

我可以通过将数据更改为始终包含尾随换行符来解决这个问题,或者修改将框文本设置为始终添加换行符的点。但这两个看起来都很混乱。没有办法让RichTextBox的链接更像web浏览器中的链接吗

我可以通过创建一个示例WinForms应用程序,放入一个RichTextBox,并使用设计器将文本设置为“”来重现此行为。链接下方的任何位置都将显示手动光标

我使用的是Windows7/VS2010/C#/.NETFramework4.0

谢谢你的建议

链接下方的任何位置都将显示手动光标

您需要在链接下方放置一个换行符以查看文本光标,而不是手动光标。这是故意的

我可以通过将数据更改为始终包含 尾部换行符,或修改要设置文本的点 该框将始终添加一个。但这两个看起来都很混乱。没有吗 使RichTextBox的链接更像web中的链接的方法 浏览器

不,在后面放一个断线。或者将RichTexbox DetectUrls属性设置为false。或者像Hans提到的那样使用网络浏览器。或者使用第三方或开源RichTextBox控件

如果光标悬停在超链接上时触发了光标更改事件,但它不会:(

如果光标悬停在超链接上时触发了光标更改事件,但它不会:(

Jeremy的评论给了我一个想法:当然,当用户悬停在超链接上时,本机RichTextBox控件确实会收到某种类型的通知,它显然没有被WinForms包装类公开

一些研究证实了我的假设。设置为检测超链接的RichTextBox控件通过向其父控件发送超链接。通过处理这些
EN_LINK
通知,可以在超链接悬停时覆盖其行为

WinForms包装器在私有代码中处理所有这些,不允许客户端直接控制此行为。但通过覆盖父窗口(即您的表单)窗口过程(),您可以手动截获
WM\u NOTIFY
消息并监视
EN\u LINK
通知

它需要一点代码,但可以工作。例如,如果您为所有
EN\u链接
通知抑制
WM\u SETCURSOR
消息,则根本看不到手动光标

[StructLayout(LayoutKind.Sequential)]
struct CHARRANGE
{
   public int cpMin;
   public int cpMax;
};

[StructLayout(LayoutKind.Sequential)]
struct NMHDR
{
   public IntPtr hwndFrom;
   public IntPtr idFrom;
   public int code;
};

[StructLayout(LayoutKind.Sequential)]
struct ENLINK
{
   public NMHDR nmhdr;
   public int msg;
   public IntPtr wParam;
   public IntPtr lParam;
   public CHARRANGE chrg;
};

public class MyForm : Form
{
   // ... other code ...

   protected override void WndProc(ref Message m)
   {
      const int WM_NOTIFY    = 0x004E;
      const int EN_LINK      = 0x070B;
      const int WM_SETCURSOR = 0x0020;

      if (m.Msg == WM_NOTIFY)
      {
         NMHDR nmhdr = (NMHDR)m.GetLParam(typeof(NMHDR));
         if (nmhdr.code == EN_LINK)
         {
            ENLINK enlink = (ENLINK)m.GetLParam(typeof(ENLINK));
            if (enlink.msg == WM_SETCURSOR)
            {
                // Set the result to indicate this message has been handled,
                // and return without calling the default window procedure.
                m.Result = (IntPtr)1;
                return;
            }
         }
      }
      base.WndProc(ref m);
   }
}
不幸的是,这是最简单的部分。现在出现了丑陋的hack,我们围绕您描述的控件的默认行为展开工作,如果最后一行是超链接,它会将控件高度的其余部分视为最后一行的一部分

为此,我们需要获取鼠标指针的当前位置,并将其与控件检测到的超链接文本的位置进行比较。如果鼠标指针位于超链接线内,我们将允许默认行为并显示手光标。否则,我们将抑制手光标。有关pote,请参阅下面的注释代码更好地解释该过程(显然,
rtb
是RichTextBox控件):


测试和工作…但我有没有提到这是一个丑陋的黑客行为?将其视为一个概念证明。我当然不建议在生产代码中使用它。我与Hans和Jeremy的意见相当一致,即您应该采取更简单的方法添加换行符,或者使用更合适的控件来显示宣传rlinks.

添加换行符会很麻烦吗?拜托,这是一个可以大声叫喊的richTEXTbox!如果你想让它像浏览器一样使用WebBrowser。我认为使用换行符是最好的方法,不会很不方便。如果有其他解决方案(继续使用richTEXTbox),它一定比你指出的更复杂。@KingKing我想我找到了一种使用RichTextBox的方法;请参见下面的答案。但肯定更复杂!:-)谢谢——这很酷。我同意,这是一个相当丑陋的黑客攻击。我将试着找到一个满足我需要的第三方控件。
protected override void WndProc(ref Message m)
{
   const int WM_NOTIFY    = 0x004E;
   const int EN_LINK      = 0x070B;
   const int WM_SETCURSOR = 0x0020;

   if (m.Msg == WM_NOTIFY)
   {
      NMHDR nmhdr = (NMHDR)m.GetLParam(typeof(NMHDR));
      if (nmhdr.code == EN_LINK)
      {
         ENLINK enlink = (ENLINK)m.GetLParam(typeof(ENLINK));
         if (enlink.msg == WM_SETCURSOR)
         {
            // Get the position of the last line of text in the RichTextBox.
            Point ptLastLine = rtb.GetPositionFromCharIndex(rtb.TextLength);

            // That point was in client coordinates, so convert it to
            // screen coordinates so that we can match it against the
            // position of the mouse pointer.
            ptLastLine = rtb.PointToScreen(ptLastLine);

            // Determine the height of a line of text in the RichTextBox.
            // 
            // For this simple demo, it doesn't matter which line we use for
            // this since they all use the same size and style. However, you
            // cannot generally rely on this being the case.
            Size szTextLine = TextRenderer.MeasureText(rtb.Lines[0], rtb.Font);

            // Then add that text height to the vertical position of the
            // last line of text in the RichTextBox.
            ptLastLine.Y += szTextLine.Height;

            // Now that we know the maximum height of all lines of text in the
            // RichTextBox, we can compare that to the pointer position.
            if (Cursor.Position.Y > ptLastLine.Y)
            {
               // If the mouse pointer is beyond the last line of text,
               // do not treat it as a hyperlink.
               m.Result = (IntPtr)1;
               return;
            }
         }
      }
   }
   base.WndProc(ref m);
}