Элемент управления Timer в ASP.NET AJAX Framework

ОГЛАВЛЕНИЕ

Элемент управления Timer, который является главной темой данной статьи, вызывает постбэк каждый раз, как пройдет какое-то определенное количество миллисекунд. Элемент управления Timer необходим тогда, когда намнужнообновить часть экрана через какое-то определенное время. Например, многие финансовые веб-сайты предоставляют котировки акций, которые периодически обновляются. До появления технологии AJAX, обновление котировок означало обновление всего документа, что в результате дало бы мигание экрана и необходимость перезагрузки всего содержимого страницы (даже если изменилась всего одна котировка). Используя технологию AJAX мы можем заставить страницу асинхронно связываться с сервером для получения новых котировок каждые n миллисекунд и плавно обновить котировки на экране. Элемент управления Timer, а также UpdatePanel, делают реализацию такого механизма очень простой. Данная статья показывает, как использовать элемент Timer для того, чтобы вызвать частичный постбэк каждые пять секунд. Она также показывает, как запустить и остановить Timer ,используя как код клиентской стороны, так и серверной. Читайте далее, чтобы узнать больше об этом!


Выполняем постбэк каждые n миллисекунд

Элемент управления Timer создан для того, чтобы периодически вызывать постбэк. Его свойство Interval указывает количество миллисекунд до запуска постбэка. Во время постбэка, вызывается событие Tick Timer .

И это все! Элемент управления Timer по умолчанию вызывает постбэк для всей страницы, но вам необходимо, чтобы он вызывал частичный постбэк. Это может быть осуществлено  двумя  путями:

  • Путем расположения элемента Timer вместе с UpdatePanel. Когда срабатывает Timer он вызывает постбэк, но поскольку он находится в UpdatePanel, постбэк становится частичным.
  • Путем расположения элемента Timer за пределами UpdatePanel, но при этом добавив его как триггер UpdatePanel. Просмотрите статью "Используем UpdatePanel" на предмет вызова частичного постбэка из UpdatePanel, используя при этом элементы управления, находящиеся за пределами UpdatePanel.
Для того чтобы обновить экран или выполнить какие-либо другие действия во время постбэка, вызванного элементом Timer, создайте обработчик события для события Tick.

Файлы, доступные в конце данной статьи, включают в себя файл Timer.aspx, который демонстрирует использование элемента Timer для того, чтобы асинхронно обновлять содержимое UpdatePanel каждые пять секунд. Более конкретно - данная страница отображает текущие котировки акций фиктивной компании. Чтобы получить данную функциональность, начните с создания новой; настройте ее так, чтобы она использовала ASP.NET AJAX Framework путем добавления элемента ScriptManager на страницу. Также добавьте элемент управления Label, названный CurrentTime, который мы будет использовать для отображения времени последнего обновления страницы, произведенного после полного постбэка. Далее добавьте элемент управления UpdatePanel и расположите содержимое, которое должно быть обновлено в нем каждые пять секунд. Я добавил три веб-элемента управления в UpdatePanel:

  • Элемент управления Label, названный StockPrice, который используется для отображения котировок акции компании.
  • Элемент управления Image , который отображает либо картинку с мешком денег, либо обанкротившегося парня, в зависимости от текущих котировок акции. (Немного юмора не помешает.)
  • Другой элемент управления Label, названный CurrentPanelTime, отображает время последнего обновления UpdatePanel.
Я также добавил элемент управления Timer в UpdatePanel и установил его свойство Interval в значение 5000. Каждые пять секунд Timer будет срабатывать, тем самым вызывая частичный постбэк, а также вызывая событие Tick.

На данный момент декларативная разметка вашей страницы должна выглядеть примерно так:

<asp:ScriptManager ID="MyManager"  runat="server">
</asp:ScriptManager>

This page last experienced a "full" postback at:
<asp:Label ID="CurrentTime" runat="server"></asp:Label></p>

<asp:UpdatePanel ID="MyUpdatePanel" runat="server">
   <ContentTemplate>
      Current stock price:
      <asp:Label ID="StockPrice" runat="server" Font-Bold="True"></asp:Label><br />
      <asp:Image ID="ResultsImage" runat="server" Width="100px" /><br />
      <br />
      
      The UpdatePanel was last refreshed at:
      <asp:Label ID="CurrentPanelTime" runat="server"></asp:Label>
      <br />
      
      <asp:Timer ID="MyTimer" runat="server" Interval="5000">
      </asp:Timer>

   </ContentTemplate>
</asp:UpdatePanel> 

Добавьте метод, названный UpdateStockPrice, в страничный класс code-behind. Данному методу необходимо определить текущую котировку акции, отобразить ее в элементе StockPrice Label, и загрузить соответствующее изображение. Как видно из нижеприведенного кода, котировка акции просто-напросто является наугад выбранным числом в интервале от 0 до 100. Более того, свойство ForeColor элемента StockPrice установлено в красном цвете (Red) и отображается изображение с банкротом в случае, если котировка акции меньше ,чем $50.00; свойство ForeColor установлено в зеленом цвете (Green) и показывается изображение с мешком денег в случае, если цена акции больше либо равна $50.00.

private void  UpdateStockPrice()
{
   // Определяем новую (случайную) цену акции
   Random rnd = new Random();
   decimal quote = Convert.ToDecimal(rnd.NextDouble()) * 100.0M;
   StockPrice.Text = quote.ToString("c");

   if (quote < 50.0M)
   {
      StockPrice.ForeColor = System.Drawing.Color.Red;
      ResultsImage.ImageUrl = "~/Images/Broke.gif";
   }
   else
   {
      StockPrice.ForeColor = System.Drawing.Color.Green;
      ResultsImage.ImageUrl = "~/Images/MoneyBags.jpg";
   }

Необходимо вызвать метод UpdateStockPrice в случае, если страница была впервые загружена, а также когда вызывается событие Tick элемента Timer. Создайте событие Page_Load в классе code-behind и установите свойство Text обоих элементов Label в текущее значение времени. Также вызовите метод UpdateStockPrice, если Page.IsPostback  равно значению False (т.е. страница посещена впервые, а не после постбэка):

protected void Page_Load(object sender,  EventArgs e)
{
   CurrentTime.Text = DateTime.Now.ToLongTimeString();
   CurrentPanelTime.Text = DateTime.Now.ToLongTimeString();

   // Обновить котировку акции во время первого посещения страницы (а не во время последующих постбэков)
   if (!Page.IsPostBack)
      UpdateStockPrice();

Далее создайте обработчик для события Tick элемента Timer и, находясь там, вызовите метод UpdateStockPrice:

protected void MyTimer_Tick(object  sender, EventArgs e)
{
   // Обновить котировку акции
   UpdateStockPrice();
}

Имея данную декларативную разметку и код, посетите страницы при помощи браузера. Каждые пять секунд Timer будет вызывать частичный постбэк, вырабатывается текущая котировка акции, и экран обновляется (точнее только часть экрана). Следующее изображение демонстрирует страницу во время первого визита. Заметьте, что время последнего совершенного полноценного постбэка (первоначальная загрузка страницы) и время последнего обновления UpdatePanel совпадают.


Заметьте, что время, показанное в UpdatePanel, на пять секунд больше, чем время загрузки страницы.



 

Запуск и остановка элемента управления Timer

По умолчанию, элемент управления Timer начинает отсчет с момента загрузки страницы, и продолжает вызывать постбэки каждые n миллисекунд. Если вам необходимо остановить отсчет в элементе Timer, у вас в распоряжении два пути:

  • Отключить Timer на серверной стороне, или
  • Остановить Timer на клиентской стороне.

Элемент управления Timer обладает свойством Enabled ,которое указывает на то, активен Timer или нет. Это свойство серверной стороны - если вы хотите поменять данное значение, то вам потребуется выполнить какой-либо постбэк (будь то полноценный постбэк, либо частичный). Используя опцию клиентской стороны, мы можем применить JavaScript для того, чтобы остановить (либо запустить) элемент Timer, что освобождает от постбэка. Тем не менее, опция клиентской стороны требует немного больше кода JavaScript, чем требуется на серверной части. Приложения данной статьи включают в себя демо-код как для серверной стороны (TimerPause.aspx), так и для клиентской (TimerPauseClient.aspx). Давайте разберем оба подхода.

Чтобы реализовать серверную функциональность, я дополнил пример, использующий элемент Timer, путем добавления элемента Button в UpdatePanel. Я также установил свойство Text данного элемента в значение "Pause" и создал обработчик события Click. В обработчике события я меняю значение свойства Enabled элемента управления Timer и обновляю свойство Text элемента Button, изменяя его с "Pause" на "Resume" при остановке таймера, либо с "Resume" обратно на "Pause" - при его запуске. Я также вызываю метод UpdateStockPrice при запуске таймера, тем самым восстановление элемента Timer мгновенно обновляет котировку акции (в отличие от случая, когда нам пришлось бы ждать пять секунд до того, как будет задействован элемент Timer).

protected void  ToggleServerSide_Click(object sender, EventArgs e)
{
   if (MyTimer.Enabled)
   {
      MyTimer.Enabled = false;
      ToggleServerSide.Text = "Resume";
   }
   else
   {
      MyTimer.Enabled = true;
      ToggleServerSide.Text = "Pause";

      // Обновить котировку акций
      UpdateStockPrice();
   }
}

Чтобы запустить или остановить элемент Timer с клиентской стороны, вам необходимо получить ссылку на элемент Timer и затем вызывать его соответствующую функцию - _startTimer или _stopTimer. Приложения в конце данной статьи  содержат в себе очень полезную JavaScript функцию, названную ToggleTimer, которая, как подразумевает ее название (переключатель таймера), переключает статус элемента Timer при помощи методов клиентской стороны. Данный метод требует два входных параметра: ссылку на кнопку (кнопка "Pause"/"Resume") и значение id элемента управления Timer. Оно получает ссылку на элемент управления Timer при помощи функции Client Library $get(id)из ASP.NET AJAX Framework и затем, в зависимости от того, активен таймер или нет, останавливает либо запускает его. Значение атрибута кнопки value, которое соответствует тексту, отображенному элементом Button, также обновляется. Вот сама функция JavaScript.

var timerEnabled = true;
function ToggleTimer(btn, timerID)
{
   // Переключить состояние активности таймера
   timerEnabled = !timerEnabled;

   // Получаем ссылку на Timer
   var timer = $find(timerID);

   if (timerEnabled)
   {
      // Запускаем таймер
      timer._startTimer();
      
      // Мгновенно выставляем флаг
      timer._raiseTick();

      btn.value = 'Pause';
   }
   else
   {
      // Останавливаем таймер
      timer._stopTimer();

      btn.value = 'Resume';
   }

Данная функция находится в файле TimerLogic.js в папке ~/Scripts. Чтобы внедрить ее в конкретную веб-страницу ASP.NET, добавьте коллекцию Scripts из ScriptManager. Чтобы использовать функцию JavaScript, добавьте HTML для кнопки на UpdatePanel и в его клиентском обработчике события onclick вызовите функцию ToggleTimer, передавая ссылку на данную кнопку, а также значение id элемента Timer клиентской стороны. (Заметьте, что клиентская сторона доступна посредством свойства ClientID элемента Timer .)

 <asp:ScriptManager ID="MyManager"  runat="server">
   <Scripts>
      <asp:ScriptReference Path="~/Scripts/TimerLogic.js" />
   </Scripts>
</asp:ScriptManager>

<asp:UpdatePanel ID="MyUpdatePanel" runat="server" UpdateMode="Conditional">
   <ContentTemplate>
      Current stock price: ...

      <input type="button" id="btnToggleTimer" value="Pause" onclick="ToggleTimer(this, '<%=MyTimer.ClientID%>');" />

      ...
   </ContentTemplate>
</asp:UpdatePanel>

Следующее изображение демонстрирует страницу с действующей кнопкой Pause/Resume. Когда страницу посещают впервые элемент Timer активен; следовательно, на кнопке Button написано "Pause".


Нажатие на кнопку "Pause" вызывает остановку элемента Timer и заменяет текст кнопки на значение "Resume". Timer не начнет отсчет до тех пор, пока не будет нажата кнопка "Resume".



Вывод

Элемент упрвления Timer из ASP.NET AJAX Framework делает вызов постбэка каждые n миллисекунд более простой процедурой (точнее говоря, частичного постбэка). Установите свойство Interval элемента Timer в соответствующее количество миллисекунд и затем создайте обработчик для события Tick данного элемента. И это все! Написав немного больше кода, вы сможете добавить больше функциональности для остановки и перезапуска элемента управления Timer.

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

Scott Mitchell

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