改进LinkLabel-使用系统手动光标并更改链接颜色

时间:2019-01-12 14:49:06

标签: c# .net winforms linklabel

LinkLabel控件存在一些烦人的问题:

  • 默认情况下,它不使用任何系统颜色(Color.Blue属性使用SystemColors.HotTrack而不是LinkColor
  • 它使用了旧的,丑陋的,别名化的手形光标

我找到了以下答案here,声称可以解决光标问题:

using System.Runtime.InteropServices;

namespace System.Windows.Forms {
    public class LinkLabelEx : LinkLabel {
        private const int IDC_HAND = 32649;

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr LoadCursor(IntPtr hInstance, int lpCursorName);

        private static readonly Cursor SystemHandCursor = new Cursor(LoadCursor(IntPtr.Zero, IDC_HAND));

        protected override void OnMouseMove(MouseEventArgs e) {
            base.OnMouseMove(e);

            // If the base class decided to show the ugly hand cursor
            if(OverrideCursor == Cursors.Hand) {
                // Show the system hand cursor instead
                OverrideCursor = SystemHandCursor;
            }
        }
    }
}

但是,此解决方案并不完美。例如,将旧的难看的光标悬停在其上之前会闪烁一帧,然后显示正确的光标。

我还阅读了 ComCtl32.dll 中的本机SysLink控件,该控件没有问题,但是我找不到在C#/中使用它的好方法WinForms。但是无论如何,我还是希望使用纯.NET解决方案。

如何通过解决上述问题来使LinkLabel控件更好?

1 个答案:

答案 0 :(得分:2)

关于颜色,该控件具有一些属性,可用于更改链接颜色:LinkColorActiveLinkColorVisitedLinkColorDisabledLinkColor

这些属性的默认值来自存储在HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Settings注册表项中的Internet Explorer设置。

要使用不同的颜色,可以根据自己的喜好设置这些属性。例如,您可以将LinkColor设置为SystemColors.HotTrack或按照w3org的建议选择颜色,并使用#0000EE作为默认链接颜色,并使用#551A8B作为访问链接, #FF0000用于活动链接。

关于闪烁,这是因为共享的代码是在基类更改了光标之后将光标设置在鼠标移动上。结果,在设置新光标之前,有可能使基类光标闪烁。要解决此问题,您需要处理WM_SETCURSOR,并在必要时将光标设置为系统手形光标。

using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
public class MyLinkLabel : LinkLabel
{
    public MyLinkLabel()
    {
        this.LinkColor = Color.FromArgb(0x00, 0x66, 0xCC);
        this.VisitedLinkColor = Color.FromArgb(0x80, 0x00, 0x80);
        this.ActiveLinkColor = Color.FromArgb(0xFF, 0x00, 0x00);
    }
    const int IDC_HAND = 32649;
    const int WM_SETCURSOR = 0x0020;
    const int HTCLIENT = 1;
    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    static extern IntPtr LoadCursor(IntPtr hInstance, int lpCursorName);
    [DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
    public static extern IntPtr SetCursor(HandleRef hcursor);

    static readonly Cursor SystemHandCursor = 
        new Cursor(LoadCursor(IntPtr.Zero, IDC_HAND));
    protected override void WndProc(ref Message msg)
    {
        if (msg.Msg == WM_SETCURSOR)
            WmSetCursor(ref msg);
        else
            base.WndProc(ref msg);
    }
    void WmSetCursor(ref Message m)
    {
        if (m.WParam == (IsHandleCreated ? Handle : IntPtr.Zero) &&
           (unchecked((int)(long)m.LParam) & 0xffff) == HTCLIENT)
        {
            if (OverrideCursor != null)
            {
                if (OverrideCursor == Cursors.Hand)
                    SetCursor(new HandleRef(SystemHandCursor, SystemHandCursor.Handle));
                else
                    SetCursor(new HandleRef(OverrideCursor, OverrideCursor.Handle));
            }
            else
            {
                SetCursor(new HandleRef(Cursor, Cursor.Handle));
            }
        }
        else
        {
            DefWndProc(ref m);
        }
    }
}