Как я могу показать всплывающую подсказку длиной более 63 символов?

Как я могу показать всплывающую подсказку длиной более 63 символов? NotifyIcon.Text имеет ограничение в 63 символа, но я видел, что VNC Server имеет более длинную подсказку.

Как я могу сделать то, что делает VNC Server?

5 ответов

Решение

На самом деле, это ошибка в установщике свойства Text. В объявлении P/Invoke для NOTIFYICONDATA в Windows Forms используется ограничение в 128 символов. Вы можете взломать его с помощью Reflection:

using System;
using System.Windows.Forms;
using System.Reflection;

    public class Fixes {
      public static void SetNotifyIconText(NotifyIcon ni, string text) {
        if (text.Length >= 128) throw new ArgumentOutOfRangeException("Text limited to 127 characters");
        Type t = typeof(NotifyIcon);
        BindingFlags hidden = BindingFlags.NonPublic | BindingFlags.Instance;
        t.GetField("text", hidden).SetValue(ni, text);
        if ((bool)t.GetField("added", hidden).GetValue(ni))
          t.GetMethod("UpdateIcon", hidden).Invoke(ni, new object[] { true });
      }
    }

Из документации MSDN по структуре Win32 NOTIFYICONDATA:

szTip

Строка с нулевым символом в конце, указывающая текст для стандартной всплывающей подсказки. Он может содержать не более 64 символов, включая завершающий нулевой символ.

For Windows 2000 (Shell32.dll version 5.0) and later, szTip can have a maximum of 128 characters, including the terminating null character.

It looks like the Windows Forms library supports the lowest common denominator here.

Расширение на правильный ответ bk1e.

Под капотом иконка в системном трее в WinForms реализована как иконка уведомлений Win32. Поэтому версия winforms имеет все ограничения как родная. Ограничение размера подсказки является лишь одним примером.

Недавно я столкнулся с похожей проблемой. Вместо того, чтобы взламывать серверную часть, я реализовал обходной путь, который использует BalloonTipText, который может вместить довольно много символов.

Всплывающая подсказка отображается в первом событии MouseMove поверх значка в области уведомлений, а всплывающая подсказка отображается в течение 2 секунд. После закрытия всплывающей подсказки ее можно снова открыть с помощью нового события MouseMove.

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

Обратите внимание, что заголовок и текст могут быть установлены в любое время в другом месте программы. Они установлены здесь только для демонстрационных целей.

РЕДАКТИРОВАТЬ: ShowBalloonTip() каскадирование пожаров MouseMove события, поэтому необходимо отключить это событие до тех пор, пока всплывающая подсказка не будет скрыта. Дополнительно, BalloonTipClosed запускается (в соответствии с документацией) только тогда, когда пользователь активно нажимает "X", хотя я заметил, что он срабатывает, когда всплывающая подсказка закрывается после истечения времени ожидания. Поэтому я добавил вспомогательный таймер для сброса состояния, вместо того, чтобы полагаться на BalloonTipClosed событие. Пересмотренный и протестированный код ниже:

    private bool balloonTipShown;
    private Timer balloonTimer;
    private void trayIcon_MouseMove(object sender, MouseEventArgs e)
    {
        if (balloonTipShown)
        {
            return;
        }
        balloonTipShown = true;
        trayIcon.MouseMove -= trayIcon_MouseMove;
        balloonTimer = new Timer();
        balloonTimer.Tick += balloonTimer_Tick;
        balloonTimer.Interval = 2005;
        balloonTimer.Start();
        trayIcon.ShowBalloonTip(2000);
    }

    void balloonTimer_Tick(object sender, EventArgs e)
    {
        balloonTipShown = false;
        balloonTimer.Stop();
        balloonTimer.Dispose();
        trayIcon.MouseMove += trayIcon_MouseMove;
    }

РЕДАКТИРОВАТЬ 2: Скриншот всплывающей подсказки с довольно большим текстом, который использует это решение, можно увидеть в блоге.

Здесь bk1e говорит, что ограничение составляет 128 символов, теперь, если вы используете UTF-16, который является родным форматом Unicode в Windows и особенно.NET, это означает, что вы ограничены 64 символами, включая NUL.

Я полагаю, что вы используете API-интерфейс Unicode, который ограничивает всплывающие подсказки до 64 16-разрядных символов (включая ноль), и что вместо этого VNC Server использует API-интерфейсы ascii (или ANSI), что позволяет использовать 128 8-разрядных символов (включая ноль).

РЕДАКТИРОВАТЬ: Этот ответ неправильный, вот полезный комментарий Коди Грей, объясняющий, почему:

Это рассуждение убедительно, но на самом деле не правильно. Когда в документации MSDN говорится о "символах", это на самом деле означает количество символов char или wchar_t в массиве (в зависимости от того, нацелен ли вы на Unicode). Таким образом, вы получите полные 128 символов, обещанных при работе в Windows 2000+. Windows 9x была ограничена до 64 символов. - Коди Грей 19 июня в 4:11"

Другие вопросы по тегам