• Microsoft .NET
  • ASP.NET
  • Контекстно-зависимая помощь для веб-страницы в ASP.NET 2.0

Контекстно-зависимая помощь для веб-страницы в ASP.NET 2.0

Некоторые реализации контекстно-зависимой справки демонстрировали такое поведение, когда при наведении указателя на область, связанную с подсказкой, она мгновенно появлялась, и в момент, когда указатель покидал область - исчезала. Данное поведение характеризуется двумя недостатками: во-первых,  если указатель был перемещен поверх  области помощи  и находится  поверх окна, то появляющееся окно может  серьезно раздражать; во-вторых, если окно помощи содержит ссылки либо слишком много текста, при этом обладая возможностью прокрутки, то при попытке перемещения указателя с области, вызвавшей появление окна помощи, на самое окно, указатель покинет область вызова помощи - и окно исчезнет.

В дополнение к данным двум недостаткам, система контекстно-зависимой помощи может быть не столь практичной для нас, разработчиков страницы. Весь скрипт и элементы <div> и <iframe> необходимо вручную добавить на страницу для того, чтобы определить окна помощи и обработчики событий onmouseover и onmouseout для области помощи. В идеале, все необходимые скрипты и разметка могут быть добавлены программным путем, одной строкой кода из класса code-behind в ASP.NET. 

В данной статье мы увидим, как можно улучшить элементарную контекстно-зависимую помощь, избавив ее от вышеперечисленных недостатков и создав класс ASP.NET 2.0 с методами для того, чтобы программно добавить окно помощи и необходимые скрипты для заданной области. Читайте далее, чтобы узнать больше об этом!

Осуществляем задержку перед открытием и закрытием окна помощи

При наведении указателя на элемент пользовательского интерфейса, обладающий подсказкой, на веб-странице либо приложении Windows подсказка появляется не сразу, а через некоторое время. Система контекстно-зависимой помощи в некоторых случаях мгновенно показывает окно помощи после того, как указатель был только наведен на область. Данная скорость может  доставлять неудобства пользователю, если он перемещает указатель по всему экрану. Даже если пользователю не было никакой необходимости видеть данную подсказку, перемещение указателя по экрану может вызвать появления окна помощи. В то же время  данные окна моментально исчезают в случае, если пользователь выйдет за границы области,  ну а мигание окна   само по себе  может быть очень  раздражающим.

Чтобы исправить это, мы можем внедрить некоторую задержку до того, как отобразим окно. То есть, когда пользователь наведет указатель на область, вызывающую окно помощи, вместо того чтобы моментально отобразить окно, мы подождем полсекунды (или сколько вы пожелаете) и затем покажем окно помощи. Если за те полсекунды указатель успел оказаться за пределами области, то мы не отобразим окно помощи.

JavaScript предоставляет функцию setTimeout(expression, delay) для осуществления задержки. Используя setTimeout, важно понимать, что функция не блокирует -  то есть когда достигается выражение setTimeout, оно добавляет выражение в очередь на выполнение после определенной задержки. Строки JavaScript будут мгновенно выполнены после функции setTimeout. Другими словами, задержка, которая  производится  до выполнения определенного выражения, является асинхронной. Поток команд не ждет в команде setTimeout пока указанная задержка не пройдет.

Чтобы достичь данного эффекта, я разделил csi_showHelpFloatWindow - который отображает определенное окно помощи - на две функции:

  • csi_showHelpFloatWindow - принимает тот же набор параметров, что и в исходном варианте, а также еще один параметр - waitDurationInMilliseconds. Параметр waitDurationInMilliseconds указывает количество миллисекунд задержки. Данная функция вызывает csi_showHelpFloatWindowInternal при помощи функции setTimeout.
  • csi_showHelpFloatWindowInternal - выполняет всю работу по отображению окна помощи.

В дополнение, нам необходима переменная флага, которая указывает на то, нужно ли отменить открытие окна или нет. Например, если пользователь наведет указатель на область помощи, то вызывается csi_showHelpFloatWindow, и функция setTimeout указывает, что функция csi_showHelpFloatWindowInternal будет вызвана после 500 миллисекунд, к примеру (полсекунды). Если пользователь перемещает указатель за пределы области до того, как пройдет это время, мы не отобразим окно. Тем не менее, функция csi_showHelpFloatWindowInternal все же будет вызвана - нет никакого способа отменить ее, основываясь на движениях курсора.

Тем самым мы используем флаг для указания того, была ли команда отменена или нет - он установлен в false в csi_showHelpFloatWindow и в true в обработчике события onmouseout области помощи. Когда выполняется функция csi_showHelpFloatWindowInternal, она всего лишь выполняется в случае, если флаг отмены равен false. Поскольку мы можем иметь окна помощи нескольких видов на одной странице (то есть окна помощи с различными windowID), одной флаговой переменной не хватит. Более того, нам необходима флаговая  переменная для каждого типа окна помощи. Это исполнимо при использовании массива  - как показано в выделенном коде JavaScript:

// Массив, хранящий в себе 'флаги' для  определения отмены открытия окна помощи
var csi_cancelOpenArray = new Array();

function csi_showHelpFloatWindow(windowID, objID, horizPadding, vertPadding, goRight, waitDurationInMilliseconds)
{
   // оставляем окно открытым
   csi_cancelOpenArray[windowID] = false;

   setTimeout("csi_showHelpFloatWindowInternal('" + windowID + "','" + objID + "'," + horizPadding + "," + vertPadding + "," + goRight + ");", waitDurationInMilliseconds);
}


function csi_showHelpFloatWindowInternal(windowID, objID, horizPadding, vertPadding, goRight)
{
   // мгновенно покидаем функцию в случае, если команда открытия была отменена
   if (csi_cancelOpenArray[windowID] == true) return;

}

Когда пользователь наводит указатель на область помощи, нам необходимо установить флаг (csi_cancelOpenArray[windowID]) в true. Это достигается путем обновления функции csi_hideHelpFloatWindow (которая, если вы помните, вызывается из события onmouseout области помощи).

function csi_hideHelpFloatWindow(windowID)
{
   // отменяем команду открытия  
   csi_cancelOpenArray[windowID] = true;

   ...
}

Данный образец повторяется для добавления задержки при выходе из области, в которой окно помощи уже открыто, и закрытия окна помощи. Данная задержка позволяет пользователю перемещать указатель с области помощи на окно с подсказкой, где они могут взаимодействовать с окном (просмотрите демо-версию ниже). Для реализации этого используется другой флаг (csi_cancelCloseArray), который установлен в false при выходе из области помощи (в функции csi_hideHelpFloatWindow ) и установлен в true при наведении указателя на область либо при наведении на само окно. Как и в случае с задержкой до открытия, данный эффект достигается путем разделения функции csi_hideHelpFloatWindow на две:

  • csi_hideHelpFloatWindow - принимает дополнительный входной параметр waitDurationInMilliseconds, который указывает количество миллисекунд паузы между выходом из области окна и закрытием самого окна. Данная функция вызывает csi_hideHelpFloatWindowInternal при помощи функции setTimeout.
  • csi_hideHelpFloatWindowInternal - выполняет всю работу сокрытия окна помощи.

 

// Массив, хранящий в себе 'флаги' для  определения отмены закрытия окна помощи
var csi_cancelCloseArray = new Array();

function csi_hideHelpFloatWindow(windowID, waitDurationInMilliseconds)
{
   // отменяем открытие
   csi_cancelOpenArray[windowID] = true;

   // подождем до сокрытия окна
   csi_cancelCloseArray[windowID] = false;

   setTimeout("csi_hideHelpFloatWindowInternal('" + windowID + "');", waitDurationInMilliseconds);
}

function csi_hideHelpFloatWindowInternal(windowID)
{
   // выходим из функции моментально если команда закрытия была отменена exit function immediately if close command has been cancelled
   if (csi_cancelCloseArray[windowID] == true) return;

}
Дополнительно csi_showHelpFloatWindow и событие onmouseover окна помощи устанавливают соответствующий флаг в csi_cancelCloseArray в значение true. Для получения более подбробной информации исследуйте полный скрипт JavaScript и библиотеку кодов в приложении, доступном в конце данной статьи.

Добавляем программно контекстно-зависимую помощь

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

  • JavaScript, необходимый для отображения и сокрытия окон помощи
  • стиль CSS, необходимый для окна помощи (это z-индекс, устанавливающий абсолютную позицию и т.д.)
  • Разметка окна помощи (теги <div> и <iframe>)
Добавление вручную данных кодов на каждую страницу может быть утомительно. Вместо этого было бы более  приемлемо связать окно помощи с областью экрана путем написания 1 строки кода из класса code-behind ASP.NET-страницы. Данный вызов метода будет автоматически внедрять необходимый код JavaScript, CSS и разметку окна помощи.

Для того чтобы реализовать это, я создал класс, названный ContextSensitiveHelp, который содержит методы относительно контекстно-зависимой помощи. ContextSensitiveHelp наследуется от класса System.Web.UI.Page. Чтобы использовать данные методы на ASP.NET-странице, настройте класс code-behind своей ASP.NET-страницы таким образом, чтобы  она наследовалась от ContextSensitiveHelp, а не от System.Web.UI.Page.

Класс ContextSensitiveHelp  содержит единственный метод, доступный с уровня страницы - AddContextSensitiveHelp, который был неоднократно перегружен. Вы должны передать данный метод как минимум:

  • элементу управления, который служит в качестве области помощи (например, элемент Label либо Image),
  • windowID (произвольная строка используемая для определения окна помощи, которое будет открыто либо закрыто), и
  • указателю ресурса (URL) веб-страницы помощи, которая будет отображена в окне помощи

Вы также можете настроить входные параметры, например, чтобы открывать окно помощи слева либо справа от области, ширину и высоту окна, отступ окна помощи от области, а также время задержки (в миллисекундах) для открытия и закрытия окон помощи. Когда вызывается метод AddContextSensitiveHelp, добавляется нужный код JavaScript или CSS (при необходимости), а также добавляется разметка окна помощи.

К  примеру, для того чтобы связать окно помощи с элементом управления Label, названным WelcomeLabel, вы можете добавить следующую строку кода в обработчик события Page_Load:

AddContextSensitiveHelp(WelcomeLabel,  "GeneralHelp", "~/HelpFiles/GeneralHelp.aspx") 

Чтобы испытать класс ContextSensitiveHelp в действии, загрузите приложение доступное в конце данной статьи.

ContextSensitiveHelp и ASP.NET Version 1.x
Класс ContextSensitiveHelp был создан в Visual Studio 2005, и он используется в веб-приложениях ASP.NET 2.0. Он использует классы и методы, являющиеся новинкой для .NET Framework 2.0 относительно порождения скрипта клиентской стороны, это означает, что оно не будет работать в приложениях ASP.NET версии 1.x. Тем не менее, новые возможности скрипта все еще могут быть выполнены в версии 1.x, но с небольшой модификацией. Для получения более подробной информации о работе со скриптом клиентской стороны в приложениях ASP.NET 1.x, изучите данный ресурс: Работа со скриптом клиентской стороны.

Вывод

Мы осуществили некоторые значительные улучшения для системы контекстно-зависимой помощи. Мы рассмотрели способ использования JavaScript функции setTimeout для добавления небольшой задержки до того, как отобразим окно помощи, а  также  как выйти из отображенного окна после того, как указатель покинет область, вызвавшую окно помощи. Более того, мы изучили класс ContextSensitiveHelp, который предоставляет простой метод создания и связывания окна с областью вызова.

Но кое-что все же требует обсуждения, например, необходимо явно указывать высоты и ширину окон помощи, тем самым настроив под содержимое. К  примеру, допустим, окно помощи имеет размеры 400x350, но его содержимое составлено в нескольких словах, и было бы  неплохо, если окно изменило бы свои размеры под содержимое, например, изменило размеры на 200x150, чтобы уменьшить пустоту в окне. В дополнение, если область помощи находится рядом с краем окна браузера (например, справа или снизу), то окно помощи в обычном случае будет обрублено границами окна. В идеале, система помощи должна рационально расположиться левее либо выше и не дать границам окна браузера обрубить свое окно. Но об этом мы поговорим в других статьях!

Веселого программирования!

Scott Mitchell

Исходный код примеров