ASP.NET Ajax a Atlas a obnovování části stránky (Atlas Framework II)
- Vložil Trupík 9/10/2006 10:05:53 PM
-
Častým nasazením Ajaxu je obnovení (update)
pouze nějaké části stránky. Zatímco serverové prvky ASP.NET
umožňují změny ve stránce pouze po postbacku (po něm musí prohlížeč
znovu načíst celou stránku), Atlas a jeho komponenta
UpdatePanel umožňuje vyznačit ve stránce místo, které se
má samostatně obnovovat, a také snadno nadefinovat podmínky, při kterých
má k obnovení dojít.
Pokud nemáte ani páru, co je to Ajax nebo Atlas, prosím, začněte
nejdříve s mým předchozím článkem na toto téma:
ASP.NET Ajax, Atlas a automatické doplňování výrazu
Obnovení části stránky (partial update) se může hodit v mnoha
případech – nějaká část stránky dostává aktuální data zvenčí
(například z webové služby), nebo se má daná část měnit po
uplynutí nějakého časového intervalu (například když chceme na stránce
střídat reklamní bannery) nebo chceme provézt update stránky na základě
uživatelovy akce (třeba kliknutí), ale je zbytečné znovu posílat celou
stránku, když chceme obnovit jen nějakou malou část. Ukážu návod na
všechny 3 kategorie.
Příklad 1. – Hodiny
Předem předesílám, že mít na webu hodiny s aktuálním časem je
podle mne zbytečné, ale je to hezký příklad. Pro příklad doporučuji
založit novou „Atlas“ Web Site, Visual Studio tak za vás vloží
nutné knihovny Atlas Frameworku.
Aspx soubor s hodinovým příkladem může vypadat takto,
Hodiny.aspx:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Hodiny.aspx.cs" Inherits="Hodiny" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<atlas:ScriptManager
runat="server"
ID="ScriptManager1"
EnablePartialRendering="true">
</atlas:ScriptManager>
<atlas:TimerControl
ID="Timer1"
Interval="1000"
runat="server"
OnTick="Timer1_Tick">
</atlas:TimerControl>
<atlas:UpdatePanel ID="UpdatePanel1" runat="server" >
<ContentTemplate>
<asp:Label ID="Label1" runat="server" />
</ContentTemplate>
<Triggers>
<atlas:ControlEventTrigger
ControlID="Timer1"
EventName="Tick" />
</Triggers>
</atlas:UpdatePanel>
</div>
</form>
</body>
</html>
A ještě Code-behind soubor:
Hodiny.aspx.cs:
using System;
public partial class Hodiny : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
UpdateTime();
}
protected void Timer1_Tick(object sender, EventArgs e)
{
UpdateTime();
}
private void UpdateTime()
{
Label1.Text = DateTime.Now.ToLongTimeString();
}
}
A teď kratičké vysvětlení (protože všechno je tak krásně
jednoduché). Komponenta ScriptManager má povolené PartialRendering, jinak by
to prostě nešlo. O to, aby se čas neustále obnovoval, se stará
komponenta TimerControl. Každou sekundu vyvolává událost Tick – tím
se zavolá funkce UpdateTime. Samotný „vnitřek“ UpdatePanelu má
dvě části – ContentTemplate, ve které je to, co panel ve výsledku
zobrazuje, a Triggers, které obsahují definice událostí, které způsobí
obnovení panelu. Triggery jsou dvou druhů – ControlEventTrigger (panel
se obnoví, při události některého z ovládacích prvků stránky,
ControlID udává, který prvek to je, a EventName která jeho událost
způsobí obnovení panelu). Ještě můžete použít
ControlValueTrigger, který se spustí, pokud se změní hodnota
vlastnosti ovládacího prvku.
Můžete zkusit příklad – čas se mění (i když se nemusí
podařit provést update každou sekundu), ale zbytek stránky se
neobnovuje.
Jen pro pořádek – takovéto hodiny ukazují serverový čas.
Pokud se vám zdá, že hodiny nepracují dostatečně svižně (každou
vteřinu je potřeba provézt dotaz k serveru a přijmout odpověď) a
zároveň by vám stačilo ukazovat klientovi čas, který má on sám
nastaven, musíte stránku přepsat jinak.
Myslím, že smysl je jasný – hodiny jsou hloupý příklad ale pokud
vyste například každých 20 vteřin chtěli vyměnit reklamní banner,
bude tento přístup naprosto dostačující.
Příklad 2. – Načítání z webové služby
Představte si, že chcete na stránce zobrazit informace, které získáte
z webové služby a udržovat je aktuální. Například zobrazovat
v úzkém proužku nejnovější zprávu ze zpravodajského serveru.
Žádnou podobnou službu se mi teď nechce hledat, takže její imitaci
napíšu sám. Může vypadat třeba takhle (Vrací stále stejnou zprávu, ale
mění se aspoň čas, pro ilustraci to stačí):
News.asmx:
<%@ WebService Language="C#" Class="News" %>
using System;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class News : System.Web.Services.WebService {
[WebMethod]
public string GetLatest() {
return DateTime.Now + " -> Jednání o vládě opět zkrachovala...";
}
}
Vlastní stránka News.aspx:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="News.aspx.cs" Inherits="News" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Untitled Page</title>
<script type="text/xml-script">
<page xmlns:script="http://schemas.microsoft.com/xml-script/2005"
xmlns:atlas="http://schemas.microsoft.com/atlas/2005">
<components>
<timer id="timer1" interval="3000" enabled="true" tick="timer1_tick" />
</components>
</page>
</script>
<script type="text/javascript">
function timer1_tick()
{
News.GetLatest(OnCallback);
}
function OnCallback(result)
{
var label = document.getElementById("Label1");
label.innerHTML = result;
}
</script>
</head>
<body>
<form id="form1" runat="server">
<div>
<atlas:ScriptManager ID="ScriptManager1" runat="server">
<Services>
<atlas:ServiceReference Path="News.asmx" />
</Services>
</atlas:ScriptManager>
<asp:Label ID="Label1" runat="server" Text="Label" />
</div>
</form>
</body>
</html>
Opět komentář: tak především, codebehindový soubor nemusí obsahovat
žádný kód. Také není použita komponenta UpdatePanel, protože
o nastavení textu v prvku label se stará pouze JavaScript. Také
pouze JavaScript volá webovou službu a čeká na její výsledek (funkce
OnCallback je zavolána v momentě, kdy je k dispozici výsledek
– ten je předán jako parametr result).
Kromě JavaScriptu stránka také obsahuje xml-script s klientskou
komponentou Timer (neplést s TimerControl!) – ta také pracuje jako
časovač, ale po uplynutí intervalu nevolá serverovou metodu, ale
JavaScriptovou funkci timer1_tick přímo na klientovi. Takže při žádném
obnovení nedochází k další interakci s www serverem (pouze se
serverem, který poskutyje webovou službu).
Příklad 3. – Načítání po uživatelově akci
Posledním příkladem, který mě napadá pro částečné updaty, je
jakési uživatelské přepínání. V praxi ho můžete vidět
například na nové homepage portálu www.atlas.cz (název portálu a název frameworku,
o kterém tu celou dobu vykládám, jsou shodné jen náhodou). Kromě
UpdatePanelu k podobné funkci použiju také serverovou ASP.NET
komponentu MultiView, která je připravená na toto přepínání, jen ho sama
o sobě neumožňuje bez načítání celé stránky. Tam pomůže
UpdatePanel.
UserSwitch.aspx:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="UserSwitch.aspx.cs" Inherits="UserSwitch" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<atlas:ScriptManager ID="ScriptManager1" runat="server" EnablePartialRendering="true">
</atlas:ScriptManager>
<asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Přepnout" />
<div style="border: 1px solid black; width: 200px;">
<atlas:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<asp:MultiView ID="MultiView1" runat="server">
<asp:View ID="View1" runat="server">
pohled jedna pohled jedna pohled
jedna pohled jedna pohled jedna
</asp:View>
<asp:View ID="View2" runat="server">
pohled dva pohled dva pohled dva
pohled dva pohled dva pohled dva
</asp:View>
<asp:View ID="View3" runat="server">
pohled tri pohled tri pohled tri
pohled tri pohled tri pohled tri
</asp:View>
<asp:View ID="View4" runat="server">
pohled ctyri pohled ctyri pohled
ctyri pohled ctyri pohled ctyri
</asp:View>
</asp:MultiView>
</ContentTemplate>
<Triggers>
<atlas:ControlEventTrigger ControlID="Button1" EventName="Click" />
</Triggers>
</atlas:UpdatePanel>
</div>
</form>
</body>
</html>
UserSwitch.aspx.cs
using System;
public partial class UserSwitch : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Button1_Click(object sender, EventArgs e)
{
MultiView1.ActiveViewIndex = (MultiView1.ActiveViewIndex + 1) % 4;
}
}
Poslední komentář: většinu práce obstarává control MultiView. Při
stisknutí tlačítka se pouze přepne aktivní pohled. Všechny pohledy jsou
natvrdo v kódu (vnořené controly View). Ke klientovi se vždy
posílají všechna View a ta, která nejsou zobrazena, jsou součástí
ViewState.
Solution s příklady ke stažení:
PartialUpdates.zip
Perlička na závěr – první dva příklady v Opeře nedělají
nic, poslední v Opeře funguje jen tak, že se neobnovuje jen část
stránky, ale vždycky celá. V IE a Firefoxu fungují všechny
příklady.
Související články:
ASP.NET Ajax, Atlas a automatické doplňování výrazu (Atlas Framework I)
Ohodnoťte prosím užitečnost článku