Улучшение LinkLabel - используйте системный курсор и измените цвет ссылки - PullRequest
0 голосов
/ 12 января 2019

LinkLabel контроль имеет некоторые раздражающие проблемы:

  • По умолчанию он не использует системные цвета (а именно Color.Blue вместо SystemColors.HotTrack для свойства LinkColor)
  • Используется старая, уродливая, псевдоним версии курсора руки

Я нашел следующий ответ здесь , который утверждает, что решил проблему с курсором:

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;
            }
        }
    }
}

Однако это решение не идеально. Например, старый, уродливый курсор мигает в течение одного кадра, прежде чем при наведении на него курсора отображается правильный курсор.

Я также читал о встроенном элементе управления SysLink в ComCtl32.dll , в котором нет проблем, но я не могу найти хорошее решение для его использования в C # / WinForms. Однако я бы все равно предпочел чистое решение .NET.

Как можно улучшить LinkLabel элемент управления, решая вышеупомянутые проблемы?

1 Ответ

0 голосов
/ 13 января 2019

Что касается цвета, у элемента управления появились свойства, позволяющие изменить цвет ссылки: LinkColor, ActiveLinkColor, VisitedLinkColor и DisabledLinkColor.

Значения по умолчанию для этих свойств получены из настроек Internet Explorer, которые хранятся в разделе реестра HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Settings.

Чтобы использовать разные цвета, вы можете установить эти свойства в зависимости от ваших предпочтений. Например, вы можете установить 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);
        }
    }
}
...