Введение
Часто бывает полезно отображать сообщения «пожалуйста, подождите» или анимированные изображения GIF во время процесса отправки формы веб-приложения, особенно если процесс отправки занимает много времени. Недавно я разработал программу подачи опросов, в которой внутренние пользователи загружают таблицы Excel через веб-страницу. Программа вставляет загруженные данные электронной таблицы в базу данных. Этот процесс занимает всего несколько секунд, но даже если это несколько секунд, с точки зрения веб-страницы это очень очевидный процесс ожидания. Во время тестирования программы некоторые пользователи неоднократно нажимали кнопку загрузки. Поэтому полезно предоставить визуальное сообщение, сообщающее людям о том, что загрузка продолжается. И одновременно скройте кнопку загрузки, чтобы предотвратить несколько кликов. Представленный здесь элемент управления является подклассом элемента управления Button, который демонстрирует, как инкапсулировать код JavaScript на стороне клиента в серверный элемент управления ASP.NET для предоставления удобных функций.
Хотя существует множество примеров JavaScript для достижения этой цели, я обнаружил некоторые проблемы, когда пытался инкапсулировать эти функции в элементы управления ASP.NET. Сначала я попытался сделать кнопку недействительной через обработчик onclick javascript и заменить ее другим текстом. Но мне это показалось очень сложным, так как это будет мешать функции события щелчка на стороне сервера asp.net. Что наконец сработало и имело хорошую поддержку для разных браузеров, так это отображение кнопки в теге div. Элемент div может быть скрыт и не мешать событию щелчка asp.net.
Использование элемента управления.
Функции PleaseWaitButton, являющегося производным от обычного элемента управления «Кнопка», в основном те же. Он использует три дополнительных свойства для управления отображением сообщений или изображений «Пожалуйста, подождите» при нажатии кнопки.
Пожалуйста, подождитеТекст
Это текстовое сообщение на стороне клиента, которое отображается и, если оно присутствует, заменяет кнопку при нажатии кнопки.
Пожалуйста, подождитеИзображение
Это файл изображения (например, анимированное изображение в формате gif), которое отображается и, если оно присутствует, заменит кнопку при нажатии на нее. Этот атрибут станет атрибутом src в теге <img>.
Пожалуйста, подождите, тип
Одно из значений перечисления PleaseWaitTypeEnum: TextOnly, ImageOnly, TextThenImage или ImageThenText. Он управляет расположением сообщений и изображений.
Ниже приведен пример файла .aspx, демонстрирующего PleastWaitButton с наборами PleaseWaitText и PleaseWaitImage.
<%@ Язык страницы="C#" %>
<%@ Регистрация TagPrefix="cc1" Namespace="JavaScriptControls"
Assembly="PleaseWaitButton" %>
<script runat="server">
частная пустота PleaseWaitButton1_Click (отправитель объекта, System.EventArgs e)
{
// Обработчик события Click на стороне сервера;
// симулируем что-то, что может занять много времени,
// как загрузка файла или трудоемкая обработка на сервере
DateTime dt = DateTime.Now.AddSeconds(5);
в то время как (DateTime.Now <dt)
{
// ничего не делаем; имитируем 5-секундную паузу;
}
// в конце цикла выводим сообщение об успехе
// и скрываем форму отправки
PanelSuccess.Visible = правда;
PleaseWaitButton1.Visible = ложь;
}
</скрипт>
<html>
<голова>
<title>Тестирование PleaseWaitButton</title>
</голова>
<тело>
<form id="Form1" метод="post" runat="server">
<P>Тестирование элемента управления PleaseWaitButton.</p>
<cc1:PleaseWaitButton id="PleaseWaitButton1" runat="сервер"
Text="Нажмите меня, чтобы начать трудоемкий процесс"
PleaseWaitText="Пожалуйста, подождите"
PleaseWaitImage="pleaseWait.gif"
OnClick="PleaseWaitButton1_Click" />
<asp:Panel id="panelSuccess" runat="server"
видимый="ложь">
Спасибо за отправку этой формы. Вы действительно.
самый крутой пользователь, которому я когда-либо имел удовольствие служить.
Нет, правда, я серьезно. Конечно, были и другие.
но на самом деле ты в классе один.
</asp:Панель>
</форма>
</тело>
</html>
Как это работает
Элемент управления PleaseWaitButton отображает стандартную кнопку ASP.NET внутри тега <div>. Он также отображает пустой тег <div> для информации/изображения. При нажатии кнопки скрытие кнопки и отображение информации контролируется функцией Javascript (см. клиентскую функцию ниже). Для удобства реализация всего необходимого клиентского кода JavaScript осуществляется серверным элементом управления PleaseWaitButton.
Поскольку PleaseWaitButton реализует собственный обработчик onclick в JavaScript, нам необходимо предпринять некоторые дополнительные шаги, чтобы сохранить исходный обработчик onclick и позволить элементу управления корректно запускать некоторый код проверки на стороне клиента. Чтобы достичь этой цели, мы сначала восстанавливаем базовый класс Button в строковый буфер, а затем умело обрабатываем его, включая определенный нами код onclick.
защищенное переопределение void Render (вывод HtmlTextWriter)
{
// Выводим HTML-код кнопки (с атрибутами)
// в фиктивный HtmlTextWriter
StringWriter sw = новый StringWriter();
HtmlTextWriter wr = новый HtmlTextWriter (sw);
base.Render(запись);
строка sButtonHtml = sw.ToString();
wr.Закрыть();
SW.Закрыть();
// теперь изменяем код, включив в него обработчик onclick
// с нашей функцией PleaseWait(), вызванной соответствующим образом
// после любой проверки на стороне клиента.
sButtonHtml = ModifyJavaScriptOnClick(sButtonHtml);
// перед рендерингом кнопки выводим пустой <div>
// который будет заполнен на стороне клиента через JavaScript
// с сообщением «пожалуйста, подождите»
output.Write(string.Format("<div id='pleaseWaitButtonDiv2_{0}'>",
this.ClientID));
output.Write("</div>");
// отображаем кнопку в собственном инкапсулирующем теге <div>
output.Write(string.Format("<div id='pleaseWaitButtonDiv_{0}'>",
this.ClientID));
вывод.Write(sButtonHtml);
вывод.Write("</div>");
}
Этот метод уменьшения кнопки до строкового буфера и последующей обработки ее содержимого при нажатии, безусловно, является хаком, но он позволяет нам реализовать стандартный код проверки в классе родительской кнопки, а затем реализовать вызов функции PleaseWait() Javascript. Без этого нам пришлось бы реализовать вызов функции PleaseWait() в атрибуте onclick перед кодом проверки, если только мы не хотим полностью переопределить рендеринг атрибута родительского класса Button. Таким образом, даже если на странице есть ошибки ввода, это приведет к скрытию кнопки и отображению сообщения «пожалуйста, подождите», которое нам не нужно. Поэтому мы должны заставить нашу клиентскую функцию PleaseWait() в обработчике onclick появиться после проверки клиентской страницы.
Изменение атрибута onclick происходит в функции ModifyJavaScriptOnClick(). Эта функция получает HTML-строку, отображаемую кнопкой, и проверяет наличие атрибута onclick. Если да, эта функция проверяет, используется ли код проверки на стороне клиента. В этом случае определенная нами функция PleaseWait() будет добавлена в конец существующего кода onclick, сразу после логической переменной Page_IsValid, проверенной клиентом. Эта переменная указывает, используется ли элемент управления проверкой. Если значение Page_IsValid равно false, сообщение «Пожалуйста, подождите» отображаться не будет. Отображается, если это правда.
частная строка ModifyJavaScriptOnClick (строка sHtml)
{
// Спасибо участнику CodeProject KJELLSJ (Kjell-Sverre Jerijaervi)
// идеи кода, позволяющие кнопке работать с
строкой проверки на стороне клиента sReturn = "";
string sPleaseWaitCode = GeneratePleaseWaitJavascript();
// существует ли атрибут onclick?
Regex rOnclick = new Regex("onclick="(?<onclick>[^"]*)");
Соответствие mOnclick = rOnclick.Match(sHtml);
если (mOnclick.Success)
{
// существует существующий атрибут onclick;
// добавляем наш код в конец, если на стороне клиента;
// проверка выполнена, убедитесь, что
// мы проверяем, действительна ли страница;
строка sExisting = mOnclick.Groups["onclick"].Value;
строка sReplace = sExisting
+ (sExisting.Trim().EndsWith(";") ? "" : "; ");
if (IsValidatorIncludeScript() && this.CausesValidation)
{
// включаем код для проверки корректности страницы
строка sCode = "if (Page_IsValid)" + sPleaseWaitCode
+ "вернуть Page_IsValid;";
// добавляем наш код в конец существующего кода onclick;
sReplace = sReplace + sCode;
}
еще
{
// не беспокойтесь о том, что страница действительна;
sReplace = sReplace + sPleaseWaitCode;
}
// теперь подставляем наш код onclick
sReplace = "onclick="" + sReplace;
sReturn = rOnclick.Replace(sHtml, sReplace);
}
еще
{
// атрибут onclick не существует;
// добавляем наш
int я = sHtml.Trim().Длина - 2;
строка sInsert = " onclick = "" + sPleaseWaitCode + "" ";
sReturn = sHtml.Insert(i, sInsert);
}
return sReturn;
}
IsValidatorIncludeScript() использует описанную выше проверку, чтобы определить, существует ли стандартный блок кода Javascript для элемента управления проверкой asp.net, зарегистрированного на странице. Ниже используется простой метод для проверки наличия кода проверки и переменных, таких как Page_IsValid.
частный bool IsValidatorIncludeScript()
{
// возвращаем TRUE, если на этой странице зарегистрирован JavaScript
// для проверки на стороне клиента этот код может быть не зарегистрирован;
// если ASP.NET определяет, что он думает (правильно или неправильно)
// это браузер нижнего уровня
return this.Page.IsStartupScriptRegistered("ValidatorIncludeScript");
} Следующий метод GeneratePleaseWaitJavascript() создает функцию PleaseWait() Javascript, содержащуюся в атрибуте onclick. Мы можем определить желаемый макет, проверив свойства элемента управления.
частная строка GeneratePleaseWaitJavascript()
{
// создаем вызов функции JavaScript "PleaseWait()"
// подходит для использования в обработчике события onclick
string sMessage = "";
строка sText = _pleaseWaitText;
строка sImage = (_pleaseWaitImage != String.Empty
? строка.Формат(
"<img src="{0}" align="absmiddle" alt="{1}"/>"
, _pleaseWaitImage, _pleaseWaitText )
: String.Empty);
// устанавливаем макет на основе PleaseWaitType;
переключатель (_pleaseWaitType)
{
случай PleaseWaitTypeEnum.TextThenImage:
sMessage = sText + sImage;
перерыв;
случай PleaseWaitTypeEnum.ImageThenText:
sMessage = sImage + sText;
перерыв;
случай PleaseWaitTypeEnum.TextOnly:
sMessage = sText;
перерыв;
случай PleaseWaitTypeEnum.ImageOnly:
sMessage = sImage;
перерыв;
}
// возвращаем окончательный фрагмент кода
строка sCode = string.Format(
"PleaseWait('pleaseWaitButtonDiv_{0}',
'pleaseWaitButtonDiv2_{1}', '{2}');"
, this.ClientID, this.ClientID, sMessage);
sCode = sCode.Replace(""", """);
return sCode;
}
Если вы укажете PleaseWaitImage, вам необходимо включить дополнительный фрагмент кода Javascript, чтобы уведомить клиента о необходимости предварительной загрузки изображения. Регистрация этого сценария должна появиться в переопределенном методе OnPreRender. Зарегистрированный ключ — это имя изображения; если одно и то же изображение используется несколькими кнопками, сценарий предварительной загрузки необходимо реализовать только один раз. Здесь используется регулярное выражение для создания переменной изображения Javascript, обеспечивающей преобразование специальных символов (например, косых черт в путях к файлам) в символы подчеркивания.
защищенное переопределение void OnPreRender (EventArgs e)
{
base.OnPreRender (e);
// Если мы используем изображение, зарегистрируйте какой-нибудь JavaScript
// для предварительной загрузки изображения на стороне клиента
если (_pleaseWaitImage != String.Empty
&& _pleaseWaitType != PleaseWaitTypeEnum.TextOnly)
RegisterJavascriptPreloadImage(_pleaseWaitImage);
}
Private void RegisterJavascriptPreloadImage (строка sImage)
{
Regex rex = new Regex("[^a-zA-Z0-9]");
строка sImgName = "img_" + rex.Replace(sImage, "_");
StringBuilder sb = new StringBuilder();
sb.Append("<script Language='JavaScript'>");
sb.Append("if (document.images) { ");
sb.AppendFormat("{0} = новое изображение();", sImgName);
sb.AppendFormat("{0}.src = "{1}";", sImgName, sImage);
sb.Append(" } ");
sb.Append("</script>");
this.Page.RegisterClientScriptBlock(sImgName + "_PreloadScript",
сб.ToString());
}
Клиентские функции
Встроенный текстовый файл javascript.txt содержит <div>, который скрывает кнопку, и клиентский код, который отображает сообщение или изображение «пожалуйста, подождите». Эти коды загружаются в частный метод RegisterJavascriptFromResource(), вызываемый в переопределенном методе OnInit(). Этот метод вызывает универсальный метод GetEmbeddedTextFile(), который загружает файл в качестве источника и возвращает содержимое в виде строки.
защищенное переопределение void OnInit (EventArgs e)
{
base.OnInit(е);
// код JavaScript на стороне клиента сохраняется
// во встроенный ресурс; загружаем скрипт;
// и зарегистрируем его на странице.
РегистрацияJavascriptFromResource();
}
частная пустота RegisterJavascriptFromResource()
{
// загружаем встроенный текстовый файл "javascript.txt"
// и зарегистрировать его содержимое как клиентский скрипт
строка sScript = GetEmbeddedTextFile("javascript.txt");
this.Page.RegisterClientScriptBlock("PleaseWaitButtonScript", sScript);
}
частная строка GetEmbeddedTextFile (строка sTextFile)
{
// универсальная функция для получения содержимого
// ресурса встроенного текстового файла в виде строки
// мы получим исполняемую сборку и выведем
// пространство имен, использующее первый тип в сборке
Сборка a = Assembly.GetExecutingAssembly();
String sNamespace = a.GetTypes()[0].Namespace
// со сборкой и пространством имен мы получим
//встроенный ресурс в виде потока
Stream s = a.GetManifestResourceStream(
string.Format("{0}.{1}", sNamespace, sTextFile)
);
// считываем содержимое потока в строку
StreamReader sr = новый StreamReader(s);
Строка sContents = sr.ReadToEnd();
sr.Close();
s.Close();
вернуть содержимое;
}
Встроенный ресурс javascript.txt содержит клиентский метод PleaseWait(), который выполняется в обработчике onclick кнопки Javascript. Этот код также вызывает клиентский метод HideDiv(), чтобы скрыть контейнер <div> кнопки, а затем собирает информацию или изображение в ранее пустой тег <div>, устанавливая атрибут innerHTML. Вспомогательная функция GetDiv() возвращает объект <div> с идентификатором, проверяя document.getElementById, document.all и document.layers, обеспечивая совместимость с различными браузерами. Ниже приведен весь код javascript.txt:
<script Language="JavaScript">
функция GetDiv(sDiv)
{
вардив;
если (document.getElementById)
div = document.getElementById(sDiv);
иначе, если (document.all)
div = eval("окно." + sDiv);
иначе, если (document.layers)
div = document.layers[sDiv];
еще
div = ноль;
вернуть div;
}
функция HideDiv(sDiv)
{
d = GetDiv(sDiv);
если (г)
{
if (document.layers) d.visibility = «скрыть»;
else d.style.visibility = "скрытый";
}
}
Функция PleaseWait(sDivButton, sDivMessage, sInnerHtml)
{
HideDiv(sDivButton);
вар d = GetDiv (sDivMessage);
если (d) d.innerHTML = sInnerHtml;
}
</script>
Исходная ссылка: http://www.codeproject.com/aspnet/PleaseWaitButton.asp.
Скачать исходный проект - 7 Кб
Скачать демо-проект - 30 Кб
http://www.cnblogs.com/jeffamy/archive/2006/08/20/481952.html