Использование компонента Timer

Помимо элемента управления (asp:Timer)существуют еще два альтернативных способа воспользоваться таймером, которые предоставляет пакет ASP.NET AJAX Futures CTP – использовать xml-script или программный код JavaScript.

Начнем с варианта, основанного на xml-script. Элемент, используемый в качестве таймера, называется и обладает следующими свойствами:
enabled
Чтобы активировать таймер, в это свойство нужно записать значение true
interval
Длительность интервала времени в миллисекундах, через которое произойдет событие tick

Остальная часть сценария не содержит ничего сложного. Событие tick должно быть обработано с помощью или :






Альтернативный, программный подход заключается в создании JavaScript?объекта таймера:
var timer = new Sys.Preview.Timer( );
Теперь с помощью методов доступа можно настроить таймер:
timer.set_enabled(true);
timer.set_interval(5000);
Не забудьте добавить обработчик события tick:
timer.add_tick(function( ) {
// ...
});

И наконец, таймер нужно инициализировать, в противном случае он не будет работать:
timer.initialize();

Попробуем использовать этот таймер вместе с панелями?вкладками.


В примере 16.5 используются оба способа добавления таймера в страницу. Первый таймер создается с помощью xm-script и активизирует вторую вкладку каждые пять секунд. Второй таймер создается программно. Он активизирует первую вкладку, тоже через каждые пять секунд. Однако программный код задерживает создание второго таймера на 2.5 секунды с помощью функции window.setTime out(). Таким образом, каждый из таймеров срабатывает через 5-секундный интервал, но со сдвигом относительно другого на 2.5 секунды, поэтому переключение панелей происходит каждые 2.5 секунды.

Пример 16.5. Два разных таймера сразу Timer.aspx
<%@ Page Language="C#" %>
"http://www.w3.org/TR/xhtml1/DTD/xhtml1?transitional.dtd"> ASP.NET AJAX


(body)
(asp:ScriptManager runat="server" ID="ScriptManager1")

(asp:ScriptReference name="PreviewScript.js"
assembly="Microsoft.Web.Preview" /)

(/asp:ScriptManager)
This is the first tab.(br /)
It is full of ASP.NET AJAX information.(br /)
Although it seems to be full of dummy text.




(/body)


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


Для этого мы создадим веб?службу. Нам потребуется некоторый механизм, который будет отдавать данные в виде свойств объекта, возвращаемого веб?службой. Механизм привязки данных в ASP.NET AJAX для элемента listView не способен напрямую работать с наборами данных ADO.NET. Но имеются две возможности, которые используются наиболее часто:
• Объект DataTable, точнее DataRowColection внутри DataTable.
• Собственный класс, в котором все данные помещаются в члены
класса.

Разработка собственного класса позволяет обеспечить более высокую гибкость, хотя обычно это ведет к увеличению объема программного кода. С другой стороны, объект DataRowCollection проще в использовании. Чтобы получить желаемую коллекцию записей со всеми данными, достаточно создать объект DataSet, а затем обратиться к свойству Table[0].Rows. Как и раньше, начиная с главы 1 мы будем использовать тестовую базу данных AdventureWorks. В этом примере будут запрашиваться значения полей AccountNumber и Name из таблицы Vendor.

В примере 17.1 приводится программный код веб-службы, которая возвращает данные из AdventureWorks в виде объекта DataRowCollection. Не забывайте использовать атрибут [ScriptService] для всех вебслужб, которые будут использоваться ASP.NET AJAX, и атрибут [WebMethod] для отдельных методов веб?службы, которые будут доступны клиентам.
Пример 17.1.


Веб?служба, возвращающая объект DataRowCollection ListViewVendors.asmx
<%@ WebService Language="C#" Class="Vendors" %>
using System;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Data;
using System.Data.SqlClient;
[WebService(Namespace = "http://hauser?wenz.de/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.Web.Script.Services.ScriptService]
public class Vendors : System.Web.Services.WebService
{
[WebMethod]public DataRowCollection GetVendors( )
{
SqlConnection conn = new SqlConnection(
"server=(local)\\SQLEXPRESS; Integrated Security=true;
Initial Catalog=AdventureWorks");
conn.Open( );
SqlCommand comm = new SqlCommand(
"SELECT TOP 10 AccountNumber, Name FROM Purchasing.Vendor",
conn);
SqlDataAdapter adap = new SqlDataAdapter(comm);

При использовании DataRowCollection вы должны знать об одной проблеме в ASP.NET AJAX. Когда вы попытаетесь обратиться к веб-службе из JavaScript, то получите сообщение об ошибке, указывающей на невозможность разрешить циклическую ссылку.


Данная ошибка вызвана неспособностью ASP.NET выполнить сериализацию объектов DataTable и DataRowCollection без дополнительной помощи. Такая «дополнительная помощь» обеспечивается парой конвертеров, которые необходимо поместить в файл Web.config. Загляните в раздел (если этого раздела не существует, то создайте его в узле , вложенном в узел ). Иногда бывает необходимо сделать это при переносе программного кода, написанного под Atlas, на платформу ASP.NET AJAX.

Теперь добавим следующую разметку:

type="Microsoft.Web.Preview.Script.Serialization.Converters.DataSetConverter,
Microsoft.Web.Preview"/>
type="Microsoft.Web.Preview.Script.Serialization.Converters.DataRowConverter,
Microsoft.Web.Preview"/>
type="Microsoft.Web.Preview.Script.Serialization.Converters.DataTableConverter,
Microsoft.Web.Preview"/>



Здесь сначала устанавливается максимальная длина строки в формате JSON, которая может получиться в процессе сериализации.


Вы можете использовать значение больше или меньше указанного, в зависимости от конкретных требований. Далее добавляются три конвертера – для объектов DataSet, DataRow и DataTable. Они будут выполнять преобразование объектов данных, которые мы собираемся использовать.

Как вариант, можно написать веб?службу, которая вместо объекта DataRowCollection будет возвращать массив данных. Т.к. веб?служба, которую мы разрабатываем, будет использовать поля AccountNumber и Name из AdventureWorks, то при использовании нашего собственного типа данных этот тип должен содержать два строковых свойства с именами AccountNumber и Name. В следующем фрагменте демонстрируется, как можно реализовать такой тип данных:
public class Vendor
{
string _AccountNumber;
string _Name;
public string AccountNumber
{
get
{
return _AccountNumber;
}
set
{
_AccountNumber = value;
}
}
public string Name
{
get
{
return _Name;
}
set
{
_Name = value;
}
}
public Vendor(string AccountNumber, string Name)
{
this._AccountNumber = AccountNumber;
this._Name = Name;
}
public Vendor( )
{
}
}

Ниже приводится измененная версия веб-службы, использующая пользовательский тип данных, которая выполняет запрос к таблице Purchasing.Vendors в базе данных AdventureWorks и выбирает из нее записи с данными (в нашем примере 10 первых записей), как и предыдущий пример:
[WebMethod]
public Vendor[] GetVendors( )
{
SqlConnection conn = new SqlConnection(
"server=(local)\\SQLEXPRESS; Integrated Security=true;
Initial Catalog=AdventureWorks");
conn.Open( );
SqlCommand comm = new SqlCommand(
"SELECT TOP 10 AccountNumber, Name FROM Purchasing.Vendor",
conn);
SqlDataReader dr = comm.ExecuteReader( );

Теперь вместо того, чтобы возвращать объект DataRowCollection, программа проходит по списку и для каждой записи в таблице создает элемент Vendor. Затем получившийся список преобразуется в массив и возвращается клиенту:
List v = new List( );
while (dr.Read( ))
{
v.Add(new Vendor(
dr["AccountNumber"].ToString( ),
dr["Name"].ToString( )));
}
return v.ToArray( );
}

В этом примере используется конструкция, впервые появившаяся в .NET Framework 2.0: обобщение (generics). Чтобы использовать обобщения, необходимо импортировать соответствующие пространства имен (System.Collections, где реализована поддержка класса List, и System.Collections.Generic). В примере 17.2 приводится полный программный код версии веб?службы, которая использует сконструированный нами тип данных Vendor.
Пример 17.2. Эта веб?служба возвращает результат нашего собственного типа
ListViewVendorsCustom.asmx
<%@ WebService Language="C#" Class="Vendors" %>
using System;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Data;
using System.Data.SqlClient;
using System.Collections;
using System.Collections.Generic;
public class Vendor
{
string _AccountNumber;
string _Name;
public string AccountNumber
{
get
{
return _AccountNumber;
}
set
{
_AccountNumber = value;
}
}
public string Name
{
get
{
return _Name;
}
set
{
_Name = value;
}
}
public Vendor(string AccountNumber, string Name)
{
this._AccountNumber = AccountNumber;
this._Name = Name;
}
public Vendor( )
{
}
}
[WebService(Namespace = "http://hauser?wenz.de/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.Web.Script.Services.ScriptService]
public class Vendors : System.Web.Services.WebService
{
[WebMethod]
public Vendor[] GetVendors( )
{
SqlConnection conn = new SqlConnection(
"server=(local)\\SQLEXPRESS; Integrated Security=true;
Initial Catalog=AdventureWorks");
conn.Open( );
SqlCommand comm = new SqlCommand(
"SELECT TOP 10 AccountNumber, Name FROM Purchasing.Vendor",
conn);
SqlDataReader dr = comm.ExecuteReader( );
List v = new List( );
while (dr.Read( ))
{
v.Add(new Vendor(
dr["AccountNumber"].ToString( ),
dr["Name"].ToString( )));
}
return v.ToArray( );
}
}

Теперь вернемся к странице ASP.NET, откуда вызывается веб-служба. Веб-службы детально рассматривались в главе 5, поэтому я лишь напомню, что следует предпринять, чтобы ими можно было пользоваться. Во?первых, в xml-script следует поместить ссылку на файл .asmx. В результате на стороне клиента будет создан объект-посредник, представляющий удаленную веб?службу. Это значит, что локальный объект будет обладать теми же методами, что и удаленная служба, – вызовы локальных методов будут автоматически преобразованы в вызовы удаленных методов. Эти вызовы производятся асинхронно (как и другие запросы XMLHttpRequest, которые мы применяли в главе 3). Для обработки полученных результатов используется функция обратного вызова, которая вызывается после того, как веб?служба вернет данные.

Включая в страницу элемент управления ASP.NET AJAX ScriptManager, в первую очередь следует добавить ссылку на файл .asmx вебслужбы. Как это сделать, показано ниже:
(asp:ScriptManager runat="server")

(asp:ServiceReference Path="ListViewVendors.asmx" /)

(/asp:ScriptManager)

После загрузки страницы следует обратиться к веб-службе. Однако понятие «после загрузки страницы» несколько сбивает с толку. Например, следующий фрагмент работать не будет:


Событие load в HTML?страницы возникает сразу после загрузки всей разметки HTML-страницы. Однако вполне возможно, что к этому моменту библиотека ASP.NET AJAX и объект-посредник еще не были полностью загружены. Поэтому данный сценарий может потерпеть неудачу, выдав такое сообщение об ошибке: «Vendors not defined» (символ Vendors не определен). По этой причине лучше задержать исполнение программного кода. Для этой цели можно было бы использовать метод window.setTimeout() или подождать, пока пользователь щелкнет на кнопке, чтобы получить данные, написав что-нибудь вроде нижеследующего (функция loadVendors() будет реализована на следующем шаге):


Но еще лучше использовать специальный метод pageLoad(), который предоставляется платформой ASP.NET AJAX:


Вслед за этим можно вызвать веб-службу:


Единственное, что осталось сделать, – это написать разметку xm-script. Здесь есть некоторые сложности, но начинается она относительно просто. Сначала создается элемент

Теперь внутрь элемента можно поместить элемент . В этом теге необходимо определить значения некоторых атрибутов:
itemTemplateParentElementId

Идентификатор элемента, родительского по отношению к отдельным элементам списка. Звучит странно, но в данном примере это относится к элементу
    .
    id
    Идентификатор элемента, куда помещается результат.

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


    Внутри должны быть определены шаблон списка и шаблон элемента списка. Первый из них определяется просто – достаточно сослаться на внешний элемент
    :