Hova kattintottam?

Gyakori feladat, hogy megjelenítjük az adatokat egy weboldalon és szeretnénk biztosítani a felhasználónak, hogy valamelyik rekordra kattintva ilyen vagy éppen olyan műveletet végezzen el az adott soron. Valami oknál fogva a szokásos fejlesztői hozzáállás a feladathoz az, hogy a gomb kattintás eseménykezelőjében elkezdjük keresgélni, hogy vajon melyik rekordra kattinthatott szerencsétlen felhasználó és ilyenkor az ember hajlamos elveszni a SelectedItem, SelectedIndex, DataItem, DataRow, DataRowView, DataRowItem és társai között.

Ennél sokkal szerencsésebb hozzáállás, ha a gomb eleve tudja magáról, hogy melyik rekordhoz tartozik!

Íme egy példa, még pedig Visual Studio 2008-cal, Northwind adatbázissal és természetesen LINQ-kel. A VS 2008 remek grafikus dizájnerében létrehoztam egy LINQ to SQL adatmodellt NorthwindDataContext néven, majd ehhez konfiguráltam egy LinqDataSource vezérlőt egy ASPX oldalon:

  <asp:LinqDataSource ID="ldsNorthwind" runat="server" 
    ContextTypeName="NorthwindDataContext" TableName="Products">
  </asp:LinqDataSource>

Ezek után felhasználtam az új ListView vezérlőt, hogy megjelenítsem az adatokat az adatforrás segítségével. A célom az volt, hogy az adatok egy felsorolásos listában jelenjenek meg és mindegyik mellett legyen egy Összegez és egy Számol feliratú gomb, amivel az adott termékhez tartozó megrendeléseket tudom megszámolni és összesíteni. Ezekhez a műveletekhez definiáltam két gombot:

  <asp:ListView ID="lvProducts" runat="server" 
DataSourceID="ldsNorthwind" onitemcommand="lvProducts_ItemCommand"> <LayoutTemplate> <ul> <asp:PlaceHolder ID="itemPlaceholder" runat="server" /> </ul> </LayoutTemplate> <ItemTemplate> <li> [<asp:LinkButton id="btnSum" runat="server" Text="Összegez"
CommandName="Sum" CommandArgument='<%# Eval( "ProductID" ) %>' />] [<asp:LinkButton id="btnCount" runat="server" Text="Számol"
CommandName="Count" CommandArgument='<%# Eval( "ProductID" ) %>' />] - <%# Eval( "ProductName" ) %> </li> </ItemTemplate> </asp:ListView>

A gombnyomások kezeléséhez feliratkoztam a ListView ItemCommand eseményére. Hogy egyszerűen le tudjam kérdezni ebben az eseménykezelőben, hogy melyik gombra kattintott a felhasználó, a két gombnak eltérő CommandName értéket állítottam be. Bár szerver oldalon természetesen le lehet kérdezni a gombok feliratát is, azzal a gond, hogy azt lokalizálhatjuk, az ID értéke pedig szerintem nem annyira beszédes a kódban.

A lényeg: a gombok CommandArgument tulajdonságához odakötöttem a rekordot egyedileg azonosító ProductID mező értékét. Mivel a CommandArgument értékét egyszerű lekérdeznem az eseménykezelőben, így nem kell azzal küzdenem, hogy vajon melyik sorra kattintott a felhasználó, sőt a sor száma nem is érdekel, rögtön megkapom a rekord egyedi azonosítóját, ahonnan már csak egy ugrás a teljes rekord megszerzése.

Az ItemCommand eseménykezelő pedig így sikerült:

  protected void lvProducts_ItemCommand( object sender, ListViewCommandEventArgs e )
  {            
    NorthwindDataContext dc = new NorthwindDataContext();
    Product product = dc.Products.First( p => p.ProductID == Convert.ToInt32( e.CommandArgument ) );

    string result = default( string );

    switch( e.CommandName )
    {
      case "Sum":
        result = String.Format( "{0:c}", product.OrderDetails.Sum( o => o.Quantity * o.UnitPrice ) );
        break;
      case "Count":
        result = String.Format( "{0} darab", product.OrderDetails.Count() );
        break;
    }

    this.litResult.Text = result;
  }

Kihasználom, hogy az e.CommandArgument a rekord egyedi azonosítója és LINQ to SQL szintaktikával egyetlen sor kódot igényel a ProductID alapján egy Product példány megszerzése. Kihasználom, hogy az e.CommandName jól megkülönbözteti egymástól a két gombot és ezzel a két elvégzendő műveletet is, ami itt a példában egy összegzés és egy számlálás.

Ennél egyszerűbben talán csak úgy lehetne megoldani a feladatot, ha az egyes ListView rekordokba nem csak az ID-t, hanem a teljes objektum példányt el tudnánk menteni, azonban ezt valószínűleg sávszélesség okokból amúgy sem akarnánk.

A lényeg: ne keresgéljük a cél rekordot, mondja el az, hogy mit akar.

Mellékeltem a teljes forráskódot, ki lehet próbálni!


zip LinqBindingSampleWebSite.zip (995 kB)


Balássy György (MS RD, ASP.NET MVP, MCTS)

Balássy György (MS RD, ASP.NET MVP, MCTS) Villamosmérnök, a BME Automatizálási és Alkalmazott Informatikai Tanszékén webportálok fejlesztését oktatja. 2000 óta foglalkozik a Microsoft .NET platformjával, melynek meghonosításában jelentős szerepet vállalt előadóként, konzulensként és A .NET Framework és programozása című könyv társszerzőjeként. Az MSDN Kompetencia Központon belül a Portál Technológiák Csoport vezetője, szakterülete web alapú rendszerek fejlesztése és üzemeltetése. 2004-ben Magyarországon elsőként kapta meg a Most Valuable Professional címet, majd 2005 óta a Microsoft magyarországi regionális igazgatója. Publikációi a Technet Magazinban, az MSDN Kompetencia Központ honlapján és szakmai blogjában olvashatóak.

2007.11.19. 20:11:40 | Permalink | Hozzászólások: 1 | Tárgyszavak: , , ,


  • Event ID 36 – Class not registered

    Balássy György (MS RD, ASP.NET MVP, MCTS) Tesztelési célokból szükségem lett egy Windows XP-re és rajta IIS 5.1-re. Annak rendje és módja szerint el is indítottam az Add/Remove Windows Components varázslót, hogy telepítsem a webszervert, de sajnos a varázsló hol belefagyott a telepítésbe, hol pedig végigcsinálta, csak éppen a böngészőben 500-as HTTP hibát kaptam, mikor a http://localhost oldalt akartam megnézni. A legszebb az egészben az volt, hogy a http://localhost/mmc.gif bejött, de a http://localhost/localstart.asp nem. Tovább »
  • UpdatePanel - akkor hogy is van ez?

    Biztos sokan láttatok már ilyen-olyan tutorial videókat, mint például ez is, ami az ASP.NET alkalmazások AJAXosítása kapcsán mindösszesen arról szól, hogy tegyünk bele mindent UpdatePanel-be, és készen is vagyunk. Kétségtelenül egyszerű, kétségtelenül működik is, de vajon tényleg ez a legjobb megoldás? Tovább »


Írja meg Ön is véleményét!


Hozzászólásokat csak regisztrált, bejelentkezett felhasználóktól tudunk elfogadni!

Hozzászólások


Dávid Zoltán Dávid Zoltán  (2007.11.20. 12:28:39)

Szia, tök jó poszt! Nekem is ez a hozzáállás a szimpatikus. Ráadásul univerzális koncepció: nem csak ASP.NET-ben használható, így például a PHP oldaláról jövőknek is ismerős lehet. Örülök, hogy valaki leírta.