В этом руководстве мы рассмотрим некоторые вещи, которые вы можете делать с ASP.NET и AJAX в своих веб-приложениях. Это больше, чем просто оборачивание панели UpdatePanel
вокруг некоторых кнопок, текстовых полей и сеток!
Асинхронный JavaScript и XML
Есть много предостережений с произвольным добавлением UpdatePanels на веб-формы и надеждой на лучшее.
Хотя в этом руководстве основное внимание будет уделено другим компонентам, помимо UpdatePanel, может быть полезно взглянуть и на триггеры обратной передачи. Обертывание некоторых элементов управления в веб-форме в UpdatePanel — это дешевый и удобный способ реализации Ajax.
Обратная передача, вызванная веб-элементами управления в панели обновления, должна происходить асинхронно и не вызывать обратную передачу всей страницы. Есть, однако, много предостережений с произвольным добавлением UpdatePanels на веб-формы и надеждой на лучшее.
Существуют также ситуации, в которых можно условно вызвать обратную передачу всей страницы или, возможно, просто вызвать один метод для внутреннего метода или веб-службы, чтобы обновить небольшую часть страницы.
UpdatePanel
Элемент управления UpdatePanel указывает, какие области страницы могут обновляться асинхронно.
Давайте начнем с рассмотрения простого элемента управления UpdatePanel и некоторых вещей, которые он может делать из коробки. Элемент управления указывает, какие области страницы могут обновляться асинхронно, и, таким образом, не требуется полная обратная передача страницы.
Создайте новый проект веб-приложения ASP.NET. На страницу default.aspx
добавьте элемент управления ScriptManager
, элемент управления TextBox
с именем txtOutsideUpdatePanel
и элемент UpdatePanel. Добавьте ContentTemplate
в UpdatePanel и внутри него добавьте элемент управления Button с именем btnInsideUpdatePanel
и элемент управления TextBox
с именем txtInsideUpdatePanel
. Ниже приведены характерные линии из исходного представления:
01
02
03
04
05
06
07
08
09
10
11
|
<div>
<asp:ScriptManager ID=»ScriptManager1″ runat=»server»>
</asp:ScriptManager>
<asp:TextBox ID=»txtOutsideUpdatePanel» runat=»server»></asp:TextBox>
<asp:UpdatePanel ID=»UpdatePanel1″ runat=»server»>
<ContentTemplate>
<asp:Button runat=»server» Text=»Update» ID=»btnInsideUpdatePanel» />
<asp:TextBox runat=»server» ID=»txtInsideUpdatePanel»></asp:TextBox>
</ContentTemplate>
</asp:UpdatePanel>
</div>
|
Затем добавьте следующий код в код для этой страницы (или в тег сценария, если вы не используете этот код):
Открытый класс _Default Наследует System.Web.UI.Page Защищенный Sub Page_Load (ByVal отправитель как объект, ByVal и как System.EventArgs) обрабатывает Me.Load txtOutsideUpdatePanel.Text = Now.ToString End Sub Защищенный элемент Sub btnInsideUpdatePanel_Click (отправитель ByVal как объект, ByVal e как EventArgs) Обрабатывает btnInsideUpdatePanel.Click txtInsideUpdatePanel.Text = Now.ToString End Sub Конечный класс
Просмотрите страницу в своем веб-браузере, и вы должны увидеть два текстовых поля в веб-форме. В первом текстовом поле должна быть указана дата и время. Если вы обновите страницу, первое текстовое поле должно обновить дату и время. Нажмите кнопку, и только второе текстовое поле должно обновить дату и время. Таким образом, кнопка вызывает асинхронный почтовый ящик, потому что он находится внутри UpdatePanel.
То, что мы сделали до сих пор, — это простой способ Ajax’изации веб-формы. Мы могли бы легко поместить всю сетку с поддержкой подкачки в UpdatePanel для подкачки без мерцания.
Давайте посмотрим на все это немного подробнее.
Управление обновлениями UpdatePanel
Мы можем контролировать, когда элемент управления UpdatePanel отправляет сообщения обратно на основе событий, которые происходят с элементами управления как внутри, так и снаружи самой панели. Вот окно свойств:
В настоящее время нам интересны три свойства:
- UpdateMode : всегда (по умолчанию) или условно
- ChildrenAsTriggers : True (по умолчанию) или False
- Триггеры : набор элементов управления — обсуждается ниже
Существует три допустимых комбинации UpdateMode
и ChildrenAsTriggers
:
- Always = True UpdatePanel обновится, когда обновится вся страница, или когда дочерний элемент управления отправит ответ.
- Всегда = Неверно (неверно)
- Conditional = True UpdatePanel будет обновляться при обновлении всей страницы, или когда дочерний элемент управления отправляет назад, или триггер из-за пределов UpdatePanel вызывает обновление.
- Conditional = False UpdatePanel будет обновляться при обновлении всей страницы, или триггер вне UpdatePanel вызывает обновление. Дочерний элемент управления не вызовет обновления.
Следующее свойство, которое нас интересует, это свойство Triggers
, которое может быть двух видов:
- AsyncPostBackTrigger : вызывает асинхронное обновление UpdatePanel
- PostBackTrigger : вызывает обратную передачу страницы дочерним элементом управления UpdatePanel.
Давайте посмотрим, как они влияют на функциональность UpdatePanel. Вставьте следующий код в веб-форму, а затем код VB.Net под этим в код позади.
У нас есть две кнопки внутри панели и две кнопки снаружи. Мы подключили триггеры так, что кнопка внутри будет вызывать полный постбэк, а кнопка будет вызывать асинхронное обновление.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
<form id=»form1″ runat=»server»>
<asp:ScriptManager ID=»ScriptManager1″ runat=»server» />
<asp:UpdatePanel ID=»UpdatePanel1″ runat=»server»>
<Triggers>
<asp:AsyncPostBackTrigger ControlID=»btnAsyncTrigger» />
<asp:PostBackTrigger ControlID=»btnPostBackTrigger» />
</Triggers>
<ContentTemplate>
<asp:Label ID=»lblInnerTime» runat=»server»></asp:Label>
<br />
<asp:Button ID=»btnInnerTime» runat=»server» Text=»Inner Time» />
<asp:Button ID=»btnPostBackTrigger» runat=»server» Text=»PostBack Trigger» />
</ContentTemplate>
</asp:UpdatePanel>
<br />
<br />
<asp:Label ID=»lblOuterTime» runat=»server»></asp:Label>
<br />
<asp:Button ID=»btnOuterTime» runat=»server» Text=»Outer Time» />
<asp:Button ID=»btnAsyncTrigger» runat=»server» Text=»Async Trigger» />
</form>
|
Код-за:
Protected Sub Page_Load (ByVal отправитель как объект, ByVal и как EventArgs) lblInnerTime.Text = Сейчас lblOuterTime.Text = Сейчас End Sub
Веб-форма должна выглядеть следующим образом:
Нажатие кнопки Inner Time
вызовет асинхронную обратную передачу. Это ожидается, так как кнопка находится внутри панели обновления. Нажатие кнопки « Outer Time
приведет к полной обратной передаче страницы. Опять же, это ожидается, так как кнопка Outer Time находится за пределами панели.
Два интересных случая — это PostBack
и Async Trigger
, на которые мы PostBack
в разделе триггеров UpdatePanel. При определении триггеров нам нужно указать ControlID элемента управления, выступающего в качестве триггера, и, необязательно, событие, для которого должен сработать триггер. Если мы пропустим событие, оно сработает в событии по умолчанию для этого элемента управления.
Условные обновления UpdatePanel
Установив для свойства UpdateMode
элемента UpdatePanel значение Conditional
, а для ChildrenAsTriggers
значение False
мы можем контролировать, когда будут выполняться обновления. Асинхронная обратная передача все еще будет выполняться, но мы можем решить, когда отправлять обновленное HTML-содержимое для этой области страницы в браузер.
Вставьте следующий код на страницу ASPX:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
<form id=»form1″ runat=»server»>
<div>
<asp:ScriptManager ID=»ScriptManager1″ runat=»server»>
</asp:ScriptManager>
<asp:UpdatePanel ID=»UpdatePanel1″ runat=»server» UpdateMode=»Conditional» ChildrenAsTriggers=»False» >
<ContentTemplate>
<asp:Label ID=»lblDateTime» runat=»server» Text=»»></asp:Label><br />
<asp:Button ID=»btnAsyncPostBack1″ runat=»server» Text=»Inside UpdatePanel 1″ />
<asp:Button ID=»btnAsyncPostBack2″ runat=»server» Text=»Inside UpdatePanel 2″ />
</ContentTemplate>
</asp:UpdatePanel>
<br />
<asp:Button ID=»btnSyncPostBack» runat=»server» Text=»Outside UpdatePanel» />
</div>
</form>
|
И следующий код в его код позади:
Защищенный Sub Page_Load (ByVal отправитель как объект, ByVal и как System.EventArgs) обрабатывает Me.Load lblDateTime.Text = Сейчас End Sub Protected Sub btnAsyncPostBack1_Click (ByVal отправитель как объект, ByVal e как System.EventArgs) Обрабатывает btnAsyncPostBack1.Click 'Ничего не делать End Sub Защищенный элемент Sub btnAsyncPostBack2_Click (отправитель ByVal как объект, ByVal как объект System.EventArgs) Обрабатывает btnAsyncPostBack2.Click UpdatePanel1.Update () End Sub
Вы должны получить форму, которая выглядит следующим образом:
- Нажатие на кнопку
Inside UpdatePanel 1
вызовет асинхронную обратную передачу, но UpdatePanel не будет обновлен. - Нажатие на кнопку
Inside UpdatePanel 2
вызовет асинхронную обратную передачу, и мы явно обновляем панель. - Нажатие на
Outside UpdatePanel
приведет к нормальной обратной передаче всей страницы.
Таймеры
Мы можем периодически вызывать обратные вызовы, используя элемент управления таймера ASP.NET. Это полезно для любых регионов веб-формы, для которых нужны текущие / текущие данные, такие как новостные ленты или номера акций в реальном времени. Событие Timer.Tick
с интервалом, определенным свойством Interval
, которое составляет миллисекунды. Это событие Tick
которое мы можем использовать, чтобы вызвать асинхронный или полный постбэк.
То, как управление timer
влияет на панель, можно контролировать с помощью коллекции Triggers
.
- Как дочерний элемент управления UpdatePanel, без определенных триггеров: асинхронно обновляется на
Timer.Tick
- Снаружи, без заданных триггеров:
Timer.Tick
страницаTimer.Tick
обратно наTimer.Tick
- В качестве дочернего
PostBackTrigger
управления с определеннымPostBackTrigger
:PostBackTrigger
страницаTimer.Tick
обратно наTimer.Tick
- Снаружи с определенным AsyncPostBackTrigger: UpdatePanel асинхронно обновляется на Timer.Tick
Клиентская библиотека ASP.NET Ajax
Когда вы добавляете элемент управления
ScriptManager
в веб-форму, он делает файлы JavaScript клиентской библиотеки ASP.NET доступными для браузера пользователя.
Файлы JavaScript взяты из сборки System.Web.Extensions
. Intellisense Visual Studio также будет использовать функциональность, предоставляемую клиентской библиотекой во время разработки.
Добавьте ScriptManager
в веб-форму, добавьте новый <script> t
, введите Sys.
и вы должны увидеть целый ряд новых кусочков для игры. Мы рассмотрим некоторые пространства имен, представленные ниже.
Примеры состоят в основном из кода JavaScript, который принадлежит тегу <script>
.
Пространства имен клиентской библиотеки Ajax
- Глобальное пространство имен
-
Sys
-
Sys.Net
-
Sys.Serialization
-
Sys.Services
-
Sys.UI
-
Sys.WebForms
Глобальное пространство имен
Клиентская библиотека предоставляет нам некоторые расширения для существующих объектов JavaScript. Расширения должны сделать работу с объектами JavaScript более похожей на работу с управляемым кодом. Мы также можем очень легко расширить существующие объекты JavaScript самостоятельно. В дополнение к расширению функциональности объектов JavaScript, клиентская библиотека также автоматически подключает ряд событий, которые мы можем очень легко подключить.
Массивы:
Здесь мы используем методы расширения sort()
и join()
:
1
2
3
|
var unsortedArray = [5, 4, 3, 2, 1];
var sortedArray = unsortedArray.sort();
alert(sortedArray.join(‘,’));
|
Здесь мы расширяем объект Array
, добавляя метод min()
:
01
02
03
04
05
06
07
08
09
10
11
12
13
|
function minElement() {
var minimum = Infinity;
for (var i = 0; i < this.length; i++) {
if (this[i] < minimum) {
minimum = this[i];
}
}
return minimum;
}
var myArray = [1, 2, 3, 4, 5, 6, 7, 8, 9];
Array.prototype.min = minElement;
alert(myArray.min());
|
И здесь мы добавляем элементы в массив:
1
2
3
4
5
|
var myArray1 = [1, 2, 3];
var myArray2 = [5, 6, 7];
Array.add(myArray1, 4);
Array.addRange(myArray2, [8, 9]);
|
Sys.Debug
Мы можем использовать метод Sys.Debug.trace()
для отображения сообщений в отладчике. Это полезно, если вы хотите избежать использования вызовов alert()
всех ваших страницах. Сообщения отладчика отображаются в окне «Вывод» в Visual Studio во время сеанса отладки. Таким образом, это означает, что вам нужно «запустить» веб-проект и зайти на страницу или присоединиться к существующему процессу w3p.
В приведенном ниже фрагменте кода мы имеем простой цикл, который вызывает деление на ноль, что может вызвать проблемы в последующих вычислениях. Используя trace()
, мы можем распечатать текущее значение переменной счетчика во время выполнения цикла:
1
2
3
4
5
6
7
|
var counter = 10;
while (counter >= 0) {
counter -= 1;
Sys.Debug.trace(«Current value of counter = » + counter);
var someCalculatedValue = 10 / counter;
document.write(someCalculatedValue + » «);
}
|
Теперь давайте используем его, чтобы помочь нам спроектировать и протестировать новый объект JavaScript:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
|
Employee = function(employeeId, name) {
this.EmployeeId = employeeId;
this.Name = name;
}
Employee.prototype = {
toString: function () {
return this.EmployeeId + » : » + this.Name;
},
get_Name: function () {
return this.Name;
},
set_Name: function (newName) {
this.Name = newName;
}
}
Employee.registerClass(«Employee»);
var jamie = new Employee(123, «Jamie Plenderleith»);
Sys.Debug.trace(«Before name change : » + jamie.Name);
jamie.Name = «Jamie Plenderleith Esq.»;
Sys.Debug.trace(«After name change : » + jamie.Name);
|
События
Клиентская библиотека подключает некоторые события страницы, которые мы можем легко подключить. События для конкретной страницы:
-
pageLoad
-
pageUnLoad
И тогда мы можем получить доступ к некоторым событиям, связанным с объектом PageRequestManager
которые связаны с асинхронными PageRequestManager
:
-
InitializeRequest
-
BeginRequest
-
PageLoading
-
PageLoaded
-
EndRequest
Давайте используем trace()
чтобы увидеть, когда сработают эти события:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
<form id=»form1″ runat=»server»>
<div>
<asp:ScriptManager ID=»ScriptManager1″ runat=»server»>
</asp:ScriptManager>
<asp:UpdatePanel ID=»UpdatePanel1″ runat=»server»>
<ContentTemplate>
<asp:Button ID=»Button1″ runat=»server» Text=»Button» />
</ContentTemplate>
</asp:UpdatePanel>
<script language=»javascript» type=»text/javascript»>
var myPageRequestManager = Sys.WebForms.PageRequestManager.getInstance();
myPageRequestManager.add_initializeRequest(onInitializeRequest);
myPageRequestManager.add_beginRequest(onBeginRequest);
myPageRequestManager.add_pageLoading(onPageLoading);
myPageRequestManager.add_pageLoaded(onPageLoaded);
myPageRequestManager.add_endRequest(onEndRequest);
function pageLoad(sender, args) {
Sys.Debug.trace(«pageLoad()»);
}
function onInitializeRequest(sender, args) {
Sys.Debug.trace(«PageRequestManager.InitializeRequest»);
}
function onBeginRequest(sender, args) {
Sys.Debug.trace(«PageRequestManager.BeginRequest»);
}
function onPageLoading(sender, args) {
Sys.Debug.trace(«PageRequestManager.PageLoading»);
}
function onPageLoaded(sender, args) {
Sys.Debug.trace(«PageRequestManager.PageLoaded»);
}
function onEndRequest(sender, args) {
Sys.Debug.trace(«PageRequestManager.EndRequest»);
}
function pageUnload(sender, args) {
Sys.Debug.trace(«pageUnload()»);
}
</script>
</div>
</form>
|
Мы можем даже отменить асинхронную обратную передачу, если хотим:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
<form id=»form1″ runat=»server»>
<div>
<asp:ScriptManager ID=»ScriptManager1″ runat=»server»>
</asp:ScriptManager>
<asp:UpdatePanel ID=»UpdatePanel1″ runat=»server»>
<ContentTemplate>
<asp:Button ID=»btnUpdateDateTime» runat=»server» Text=»Update» />
<asp:Label ID=»lblDateTime» runat=»server» Text=»»></asp:Label>
</ContentTemplate>
</asp:UpdatePanel>
<script language=»javascript» type=»text/javascript»>
var myPageRequestManager = Sys.WebForms.PageRequestManager.getInstance();
myPageRequestManager.add_initializeRequest(onInitializeRequest);
function onInitializeRequest(sender, args) {
var someCondition = false;
if (!someCondition) {
Sys.Debug.trace(«someCondition=false. Aborting postback»);
args.set_cancel(true);
}
}
</script>
</div>
</form>
|
Удаленные вызовы методов
Если у пользователя особенно большой
ViewState
, это приведет к дополнительным издержкам как для них, так и для веб-сервера. Страница удаленного aspx будет проходить почти полный жизненный цикл от загрузки до выгрузки.
Теперь мы рассмотрим вызовы определенных удаленных методов. Они существуют совершенно отдельно от UpdatePanelcontrol, но они, вероятно, будут использоваться совместно для отображения результата вызова некоторого метода.
Когда в элементе управления происходит асинхронная обратная ViewState
, на веб-сервер отправляется полная обратная ViewState
страницы. Поэтому, если у пользователя особенно большой ViewState
, это приведет к дополнительным накладным расходам как для них, так и для веб-сервера. В дополнение к ViewState удаленная страница aspx будет проходить почти полный жизненный цикл от загрузки до выгрузки. Мы можем взаимодействовать с .NET 2.0 ASP.NET Web Services, .Net 4.0 WCF Services (которые в любом случае работают как .Net 2.0 ASP.NET Web Services при использовании HTTP Transport) и с ASP.NET WebForms PageMethods. Мы рассмотрим использование PageMethods.
ASPX Page Методы
Метод Page — это общедоступный (статический в C #) метод, определенный в веб-форме, украшенной System.Web.Services.WebMethod()
. В дополнение к надлежащему украшению ваших методов, ваш ScriptManager
должен иметь для свойства EnablePageMethods
значение True
. Оттуда вы должны увидеть метод, доступный через прокси-класс PageMethods
в JavaScript.
Вот очень простой пример вызова управляемого кода для выполнения вычислений. Вставьте следующее в исходное представление веб-формы:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
<form id=»form1″ runat=»server»>
<div>
<asp:ScriptManager ID=»ScriptManager1″ runat=»server» EnablePageMethods=»true»>
</asp:ScriptManager>
y = log <sub>b</sub>(x)<br />
Base b =
<input id=»txtBase» type=»text» /><br />
Value x =
<input id=»txtValue» type=»text» /><br />
Result y = <span id=»lblResult»>
<br />
<input id=»btnCalculate» type=»button» value=»Calculate» />
<script language=»javascript» type=»text/javascript»>
$addHandler($get(‘btnCalculate’), «click», btnCalculate_onclick);
function btnCalculate_onclick() {
PageMethods.CalculateLog($get(‘txtBase’).value, $get(‘txtValue’).value, calculateLog_Finished, calculateLog_Failed);
}
function calculateLog_Finished(result) {
$get(‘lblResult’).innerText = result;
}
function calculateLog_Failed(errObj) {
Sys.Debug.trace(errObj.get_message());
}
</script>
</div>
</form>
|
И к файлу с выделенным кодом добавьте следующий код:
<System.Web.Services.WebMethod ()> Открытая общая функция CalculateLog (значение ByVal как двойное, основание ByVal как двойное) как двойной Возврат Math.Log (Значение, База) Конечная функция
Вы можете видеть, что это очень простой вызов Math.Log()
, но он выполняется асинхронно, не требуя обратной передачи и без использования UpdatePanel. Обратите внимание на PageMethods.CalculateLog()
метода PageMethods.CalculateLog()
. Он принимает два параметра, требуемых методом в коде позади. В приведенном выше примере следующим параметром является обратный вызов, который необходимо выполнить после успешного завершения вызова метода, а последним параметром является обратный вызов, который необходимо выполнить при возникновении ошибки.
Однако, предостережение о PageMethods
: если класс не отображается для вас в JavaScript, вы можете попробовать несколько вещей:
- Убедитесь, что ваш метод code-behind является
Public Shared
- Убедитесь, что нет ошибок синтаксиса JavaScript
- Убедитесь, что свойство
EnablePageMethods
ScriptManager = True - Удалите и снова добавьте ScriptManager
- Выполнить восстановление
Более полный синтаксис для вызова метода PageMethod следующий:
1
|
PageMethods.MethodName(Param1, Param2 … , ParamN, CompletionCallback, FailureCallback, ContextParameter)
|
Рассмотрим нашу оригинальную сигнатуру метода CalculateLog_Finished calculateLog_Finished()
:
1
|
function calculateLog_Finished(result) {}
|
Этот метод может принимать дополнительные параметры:
1
|
function calculateLog_Finished(result, context, method) {}
|
-
Result
: результат вызова метода -
Context
: значение ContextParameter, первоначально переданное прокси-сервером PageMethods,
если есть -
Method
: метод, который был вызван — полезно при совместном использовании обратных вызовов
Дальнейшее чтение
Существует множество аспектов, связанных с Ajax, которые мы не затронули. Тем не менее, в ваших проектах могут быть интересны следующие:
- JQuery
- Использование jQuery для выполнения вызовов Ajax
- Ajax Control Toolkit
- Веб-сайт ASP.NET Ajax
- ASP.NET Ajax Видео
- Обзор Microsoft Ajax
Спасибо за прочтение!