AJAX Control Toolkit –
PopupControl II.
http://cid-8dcaf3b0da4fb828.skydrive.live.com/embedrowdetail.aspx/ACTsorozat/ACT|_XXIV|_PopupControl|_II.zip
Itt is vagyunk a cikk második felével, amelyben tovább boncolgatjuk a PopupControlExtender által nyújtott szolgáltatásokat!
PCE használata
A kicsit bonyolultabb példa
Dinamikus tartalomgenerálásra általában akkor van szükségünk, ha adatbázisokkal vagy egyéb más szöveges erőforrásokkal dolgozunk. Ezért most egy
Master-Details kapcsolatot bemutató példát fogunk elkészíteni egyetlen GridView vezérlő segítségével!
Az adatbázisunk most is a jó öreg
Northwind lesz. Alapban a GridView-ban a
Products táblából jelenítünk meg néhány mezőt. Majd a PCE segítségével aszinkron módon lekérdezzük az egyes termékek
CategoryId-jához tartozó kategória nevét a
Categories táblából. (Természetesen ennél sokkal több és értelmesebb adatot is lekérdezhetnénk, de ez csak egy demo alkalmazás, ezért nem is kell benne értelmet keresni
).
Tehát, először húzzunk a formunkra egy GridView-t, majd hozzunk hozzá létre egy új SqlDataSource-t, amely segítségével lekérdezünk néhány mezőt a Products táblából (a CategoryId oszlop legyen mindenféleképpen köztük!)! Most valahol itt kell tartanunk kód ügyileg:
<asp:GridView ID="GridView1" runat="server" AllowPaging="True" AutoGenerateColumns="False" DataKeyNames="ProductID" DataSourceID="SqlDataSource1">
<Columns>
<asp:BoundField DataField="ProductID" HeaderText="ProductID" InsertVisible="False" ReadOnly="True" SortExpression="ProductID" />
<asp:BoundField DataField="ProductName" HeaderText="ProductName" SortExpression="ProductName" />
<asp:BoundField DataField="CategoryID" HeaderText="CategoryID" SortExpression="CategoryID" />
<asp:BoundField DataField="UnitPrice" HeaderText="UnitPrice" SortExpression="UnitPrice" />
<asp:BoundField DataField="UnitsInStock" HeaderText="UnitsInStock" SortExpression="UnitsInStock" />
</Columns>
</asp:GridView>
<asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:NorthwindConnectionString %>"
SelectCommand="SELECT [ProductID], [ProductName], [CategoryID], [UnitPrice], [UnitsInStock] FROM [Products]">
</asp:SqlDataSource>
Ezek után a CategoryId oszlop mellé szúrjunk be egy TemplateField-et! Ennek az egyik legegyszerűbb módja, ha a GridView SmartTag-jében az Edit Columns… linkre kattintunk!
A felpattanó ablakban először adjunk egy TemplateField-et a Selected fields-nél lévő BoundField-ekhez, majd állítsuk be a HeaderText-jét CategoryName-re. Végül pedig az új mezőt vigyük feljebb a Selected Fields listában úgy, hogy a CategoryId alá kerüljön!
Ebbe a TemplateField-be ezek után úgy tudjuk a legegyszerűbben elhelyezni az új vezérlőket, hogy ismét elnavigálunk a GridView SmartTag-jéhez és itt legalul az Edit Templates linkre kattintunk! Ilyenkor a GW átvált szerkesztő üzemmódba, és ekkor tudjuk a mező ItemTemplate-jét módosítgatni. Húzzunk ide be egy Image vezérlőt, egy PCE-t, illetve egy Panel vezérlőt! Végül a PCE SmartTag-jében kattintsunk az Add Dynamic Populate page method linkre!
Ilyenkor a Visual Studio elhelyez az oldalunk cs fájljában egy ilyen kódrészletet:
[System.Web.Services.WebMethodAttribute(), System.Web.Script.Services.ScriptMethodAttribute()]
public static string GetDynamicContent(string contextKey)
{
return default(string);
}
Ez lesz az a webmetódus, amely előállítja majd a dinamikus tartalmat. (A függvény fölött elhelyezett attribútumok végéről természetesen nyugodtan elhagyható az Attribute() rész!) Ennek a függvénynek a megírásával kicsit később fogunk foglalkozni, ezért most térjünk vissza az aspx oldalunkra és fejezzük be a sablon szerkesztését (SmartTag >> End Template Editing)! Váltsunk át kódnézetbe és módosítsuk át a PopupControlExtender1 vezérlőnk markup-ját az alábbira:
<ajaxToolkit:PopupControlExtender ID="PopupControlExtender1" runat="server" TargetControlID="Image1" PopupControlID="Panel1" Position="Center" DynamicControlID="Panel1" DynamicServiceMethod="GetDynamicContent">
<Animations>
<OnShow>
<Sequence>
<HideAction Visible="true" />
<FadeIn duration="1" Fps="25"/>
</Sequence>
</OnShow>
<OnHide>
<Sequence>
<FadeOut duration="1" Fps="25" />
<HideAction Visible="false" />
</Sequence>
</OnHide>
</Animations>
</ajaxToolkit:PopupControlExtender>
A
DynamicServiceMethod tulajdonságon keresztül adjuk meg a dinamikus tartalmat generáló webmetódus nevét. Ha ez nem az aspx vagy az aspx.cs oldalon található, akkor értelemszerűen meg kell adnunk a
DynamicServicePath tulajdonságot is!
A
DynamicControlID annak a vezérlőnek az azonosítóját tartalmazza, amelybe publikálni szeretnénk a dinamikus tartalmat. Két dolgot fontos róla megjegyezni! Az első, hogy ezt a tulajdonságot mindig be kell állítanunk, ha nem statikus content-tel akarunk dolgozni, vagyis ha beállítjuk a
DynamicServiceMethod-ot, akkor ezt is be kell állítani! A másik fontos dolog, hogy az ennél a tulajdonságnál beállított azonosítónak nem feltétlenül kell megegyeznie a
PopupControlId-nál beállítottal, vagyis akár más panel-t is feltölthetünk dinamikus tartalommal, nem csak a popup ablakot!
Oké, ha ezzel megvagyunk, akkor térjünk vissza a dinamikus tartalmat generáló függvényhez!
Mivel a GetDynamicContent metódus egy webmetódus, ezért szinte semmilyen információt nem tudunk belőle direkt módon elérni a GridView-ról. Ezért azt kell csinálnunk, hogy a contextKey paraméteren keresztül át kell passzolnunk neki mondjuk a CategoryId értékét!
Ennek a megvalósítása rendkívül egyszerűen történik, ugyanis a PCE-t az ItemTemplate-n belül helyeztük el, és emellett még adatköthető is a vezérlő, ezért annyi dolgunk van összesen, hogy a DynamicContextKey tulajdonságát adatkössük. Vagyis az alábbi kódrészlettel kell kiegészíteni a PCE markup-ját:
DynamicContextKey='<%# Eval("CategoryID") %>’
Már csak az a feladatunk, hogy megírjuk a GetDynamicContent webmetódust. Íme az implementációja:
using System.Web.Configuration;
using System.Data.SqlClient;
…
string connstring = WebConfigurationManager.ConnectionStrings["NorthwindConnectionString"].ConnectionString;
string name = String.Empty;
using (SqlConnection conn = new SqlConnection(connstring))
{
using (SqlCommand comm = conn.CreateCommand())
{
comm.CommandText = "SELECT CategoryName FROM [dbo].[Categories] WHERE CategoryID = @ID";
comm.Parameters.Add("@ID", SqlDbType.Int);
comm.Parameters["@ID"].Value = Int32.Parse(contextKey);
conn.Open();
name = comm.ExecuteScalar() as string;
conn.Close();
}
}
return name;
A kód szerintem eléggé egyértelmű, ezért csak annyi kiegészítést tennék hozzá, hogy ha több adatot is le akarunk kérdezni az adatbázisból, és táblázatos formában akarjuk majd őket megjeleníteni, akkor mindenféleképpen StringBuilder-t használjunk a dinamikus tartalom összekonkatenálásánál!
Futtassuk az alkalmazásunkat és valami hasonlót kell tapasztalnunk!
Végezzünk el még néhány apró design-beli módosítást, hogy ki is nézzen valahogy az egész!
– GridView-nak az AutoFormat-nál állítsuk be a Professional kinézetet!
– A Panel-nek állítsuk be az alábbi stílus osztályt:
.panel_style
{
visibility: hidden;
background-color: #5D7B9D;
color: white;
padding: 5px;
text-align:center
}
– Végül pedig a PCE-nek állítsuk be az OffsetY tulajdonságát 7-re, hogy a Position-nél megadott Center az tényleg középen is legyen!
Ha ezzel megvagyunk, akkor már mondhatjuk azt, hogy adtunk egy kicsit az
UX-re is
!
A dolog egyetlen szépséghibája az, hogy ha egyszer már megjelent a popup panel az adott sorban, akkor utána már csak nehezen tudunk még egyszer rákattintani ugyanerre a képre, ugyanis a panel layer-e továbbra is ott marad, csak nem látszik, és a kurzor is átvált text-re!
Erre egy félig jó megoldás az, hogy a Panel-t nem az ItemTemplate-n belül helyezzük el, hanem a GridView-n kívül. A panel továbbra is mindig jó helyen fog megjelenni a Postion tulajdonságnak köszönhetően, és így az előző hibát ki is küszöböltük, de kaptunk helyette egy másikat!
Ez a másik probléma pedig az, hogy ha akkor, amikor a popup ablak éppen látható, rákattintunk egy másik sorban lévő képre, akkor se a
fadeout, se
fadein nem fog lejátszódni, hanem helyettük vibrálni fog a panel! (Valamit valamiért alapon.
)
PCE vs. FireFoxHát igen, elérkeztünk a dolog kényes részéhez!
Sajnos azt kell, hogy mondjam, a PCE nem igazán támogatott Extender FireFox alatt. A probléma akkor kezdődik, amikor UpdatePanel-t is szeretnénk használni. Valamilyen okból kifolyólag a benne lévő vezérlők soha se váltanak ki postback-et. Magyarul megjelenik ugyan a popup ablak, illetve ha elveszíti a fókuszt a TargetControl, akkor el is tűnik a panel (de ez is csak akkor, ha a PCE-nél nem állítottunk be semmilyen animációt!), de postback valamiért soha se történik.
Próbálkoztam azzal, hátha csak az aszinkron trigger hiányzik neki, de azzal se ment, aztán megpróbáltam azt, hogy beszórtam az összes vezérlőt egy közös UpdatePanel-be, de az se volt jó, stb. Ezek után ellátogattam a hivatalos asp.net-es oldalra (természetesen mondanom se kell, hogy az általuk készített példaalkalmazások se működnek FF alatt
) és ott rátaláltam egy új
Ajax Control Toolkit Tutorials sorozatra. Hírtelen nagyon megörültem, de sajnos itt se kaptam választ a kérdésemre, mert pont olyan példa van köztük a PCE-hez, ami nem használ UpdatePanel-t.
Visszatérve a sorozathoz, szóval június 4-én felkerült összesen 46 ilyen act-s tutorial az alábbi oldalra:
http://www.asp.net/learn/ajax-control-toolkit/?lang=cs Nekem nem nyerte el a tetszésemet a sorozat, mert szerintem rosszul van felépítve az egész és a vezérlők feléhez nincs is leírás, de ez csak egy szubjektív vélemény, ettől még lehet jó és hasznos mások számára!
Összegezve a látottakat azt kell, hogy mondjam, a PCE egy jó kis extender mindaddig, amíg nem egy éles rendszerben szeretnénk használni! Ha esetleg valaki rájönne a fenti problémák valamelyikének a megoldására, kérem tudassa velem, mert nagyon kíváncsi lennék rá! Előre is köszönöm!