ASP.NET Menu HTML Rendering

by Hannes Preishuber20. Mai 2013 10:37

Das HTML Menü Steuerelement steckt voller Magie. Es kann wie von Geisterhand auf und zuklappen, berücksichtigt die Rechte des angemeldeten Benutzers und kann sogar über einen Sitemapprovider Datengebunden werden. Aber Magier schlagen auch mal über die Strenge wenn sie von Ihren Fähigkeiten zu überzeugt sind und streben die totale Vernichtung an. So lernt man das jedenfalls aus Harry Potter. Der ach so nette Tom Riddle mutiert zu Voldemort, dem rachsüchtigen dunklen Magier der vor nichts zurückschreckt.

Nun bin ich kein fanatischer Verfechter von der Reinheit des Blutes und gebe auch Muggle Zauberern ihre Chance.

Ein Menü Control erzeugt Serverseitig HTML Code, samt CSS und Zauberscript. Als Startpunkt wird die Navigation der mobilen ppedv Kurs Anwendung verwendet.  Zwar könnte man mit einer einfach UL LI Liste das Ziel einfacher erreichen, aber der Erkenntniswert würde fehlen. Also los geht's mit “Zaubern mit Menu”

   1:<form id="form1" runat="server" data-role="page">
   2:<div data-role="content">
   3:
   4: <div>
   5: <asp:Menu ID="div1" runat="server"
   6: data-role="navbar">
   7: <Items>
   8: <asp:MenuItem NavigateUrl="~/S/2,12,14,19" Text="Windows & .NET" />
   9: <asp:MenuItem NavigateUrl="~/S/3,7" Text="Architektur&Dev" />
  10: <asp:MenuItem NavigateUrl="~/S/11" Text="Web Development" />
  11: <asp:MenuItem NavigateUrl="~/S/13,18,22" Text="SharePoint" />
  12: <asp:MenuItem NavigateUrl="~/S/5,6,20" Text="Server Administration" />
  13: <asp:MenuItem NavigateUrl="~/S/9,7" Text="Office u.a." />
  14: <asp:MenuItem NavigateUrl="~/S/4,21" Text="SQL & BI" />
  15: <asp:MenuItem NavigateUrl="~/kontakt" Text="Kontakt" />
  16: </Items>
  17: </asp:Menu>
  18: </div>
  19: 
  20:</div>
  21:</form>

Vor der vierte Folge (also bis ASP.NET 3.5) wurde daraus gar furchterbarer HTML Code, der sich dabei der dunklen Künste von HTML Tables bediente.

Wer diese dunklen Zeiten wieder heraufbeschwören möchte, kann dich dunkle Kammer von Webconfig aufsuchen und dort folgenden Zauberspruch murmeln

   1: <pages controlRenderingCompatibilityVersion="3.5" >

Seit der Stein der Weisen zurück nach Redmond gekehrt ist, serviert auch das Menu Control reines DIV, UL und LI, allerdings noch mit allerlei wundersamer Zutaten.

   1:<form method="post" action="WebForm24.aspx" id="form1" data-role="page">
   2:<div class="aspNetHidden">
   3:<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="2hB6MZYCbAUooxZUPVYswq
5ZiGyg0TutsRjTuqwqOWRyoGlxBHvPvMBmA7xs3dMHYdKdBZDFZgcT75zNssO11aaJ3fOdCsoYUd3eQBY1x7c="
/>
   4:</div>
   5: 
   6: 
   7:<script src="/WebResource.axd?d=fqV81KWLWhVg-lLAb4IT6z7dNzU96UkgnAUvd3TznA7r7jmBA8d3Ppk0
-TpQJTuNUNdLcYMr6iHiLhrQ1-FE8y8o-CmqZlIAp78DXeQ-4cw1&amp;t=634897471112455790"
type="text/javascript">
</
script>
   8:        <div data-role="content">
   9:
  10:            <div>

11: <a href="#div1_SkipLink" style="position:absolute;left:-10000px;
top:auto;width:1px;height:1px;overflow:hidden;"
>Navigationslinks überspringen</a>
<div data-role="navbar" id="div1">

  12:    <ul class="level1">
  13:        <li><a class="level1" href="S/2,12,14,19">Windows & .NET</a></li><li>
<a class="level1" href="S/3,7">Architektur&Dev</a></li><li><a class="level1" href="S/11">Web Development</a>
</li><li><a class="level1" href="S/13,18,22">SharePoint</a></li><li>
<a class="level1" href="S/5,6,20">Server Administration</a></li><li><a class="level1" href="S/9,7">
Office u.a.</a></li><li><a class="level1" href="S/4,21">SQL & BI</a></li><li>
<a class="level1" href="kontakt">Kontakt</a></li>
  14:    </ul>
  15:</div><a id="div1_SkipLink"></a>
  16:            </div>
  17: 
  18:        </div>
  19:
  20:<script type='text/javascript'>new Sys.WebForms.Menu({ element: 'div1',
disappearAfter: 500, orientation: 'vertical', tabIndex: 0, disabled: false });</script></form>

Fügt man nun noch ein wenig Jquery Mobile Kraut hinzu, erscheint ein Fenster (Aparecium).

image

Allerdings hat der dunkle Lord hier noch seine Finger im Spiel. Die Breite der Menuitems ist begrenzt. Um diesen Fluch aufzuheben, muss man einen Finite Incantatem (Gegenzauber) sprechen. Damit hebt man allerdings nur die Wirkung auf, das Sys.WebForms.Menu aus Zeile 20 bleibt.

   1:</asp:Menu>
   2:<script type="text/javascript"> Sys.WebForms.Menu = "";</script>

Um die Schönheit und Reinheit des HTML zu verbessern braucht es noch Zutaten derer Vier.

   1:   EnableViewState="false" IncludeStyleBlock="false" ClientIDMode="Static" SkipLinkText=""

Auf der Fiddler Karte erscheint so der direkte und damit optimale Weg.

image

Letztendlich  gibt es ein Happy End aber es ist das letzte Kapitel noch nicht geschrieben. Wir warten sehnsüchtig auf die  Zauberer aus Redmond.

   1: <script src="/WebResource.axd?d=fqV81KWLWhVg-lLAb4IT6z7dNzU96UkgnAUvd3TznA7r7jm
BA8d3Ppk0-TpQJTuNUNdLcYMr6iHiLhrQ1-FE8y8o-CmqZlIAp78DXeQ-4cw1&amp;t=634897471112455790"

type="text/javascript"></script>
   2:<div data-role="content">
   3: 
   4: <div>
   5: <div data-role="navbar" id="div2">
   6: <ul class="level1">
   7: <li><a class="level1" href="S/2,12,14,19">Windows & .NET</a></li>
   8: <li><a class="level1" href="S/3,7">Architektur&Dev</a></li>
   9: <li><a class="level1" href="S/11">Web Development</a></li>
  10: <li><a class="level1" href="S/13,18,22">SharePoint</a></li>
  11: <li><a class="level1" href="S/5,6,20">Server Administration</a></li>
  12: <li><a class="level1" href="S/9,7">Office u.a.</a></li>
  13: <li><a class="level1" href="S/4,21">SQL & BI</a></li>
  14: <li><a class="level1" href="kontakt">Kontakt</a></li>
  15: </ul>
  16: </div>
  17: </div>
  18: 
  19:</div>

Tags:

ASP.NET | JavaScript

mobile Websites SEO per Sitemap

by Hannes Preishuber16. Mai 2013 08:44

Ein recht junges Problem mobiler ASP.NET Websites ist die Indizierung durch Suchmaschinen wie BING oder Google. Persönlich mag ich den Begriff SEO (Search Engine Optimization) nicht, da er vorgaukelt, das man Websites für Google optimieren muss. Sollte man eigentlich nicht. Websites sollten optimal für den Benutzer sein. Der Job von Suchmaschinen wiederum ist es optimale Ergebnisse passend zu den Bedürfnissen des Users zu bringen.

In diesem Fall ist es aber anders. Parallel zu www.ppedv.at Website gibt es eine Site die fokussiert auf mobile Nutzung ist http://m.ppedv.at. Inhaltlich sehr unterschiedlich. Ruft man nun mit einem Browser die Website auf, sieht man quasi nichts. Auch der Spider (bot) der Suchmaschine sieht nichts und kann damit auch keinen Links folgen.

Laut google sollen mobile Sitemaps helfen. In den Webmaster Tools kann man sein Begehr schon mal anmelden.

image

Ich formulier das so, weil die Position und Verhalten von Google Königlich und ich Untertan (unterirdisch) bin.

In meinem Fall lasse ich nun so eine mobile Sitemap per Code generieren um immer aktuell zu sein. Entsprechende online und offline Sitemap Generatoren bieten das nicht.

Für die fixen Hyperlink wurde eine XML Vorlage angelegt. Darin kann man auch die XML Struktur gut herauslesen.

   1:<?xml version="1.0" encoding="UTF-8"?>
   2:<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
   3:xmlns:mobile="http://www.google.com/schemas/sitemap-mobile/1.0">
   4:<url>
   5:<loc>http://m.ppedv.at/</loc>
   6:<lastmod>2013-05-14</lastmod>
   7:<changefreq>monthly</changefreq>
   8:<priority>0.5</priority>
   9:<mobile:mobile/>
  10:</url>
  11:<url>
  12:<loc>http://m.ppedv.at/S/11</loc>
  13:<lastmod>2013-05-14</lastmod>
  14:<changefreq>monthly</changefreq>
  15:<priority>0.5</priority>
  16:<mobile:mobile/>
  17:</url>
  18:<url>
  19:<loc>http://m.ppedv.at/S/2,12,14,19</loc>
  20:<lastmod>2013-05-14</lastmod>
  21:<changefreq>monthly</changefreq>
  22:<priority>0.5</priority>
  23:<mobile:mobile/>
  24:</url>
  25:<url>
  26:<loc>http://m.ppedv.at/S/5,6</loc>
  27:<lastmod>2013-05-14</lastmod>
  28:<changefreq>monthly</changefreq>
  29:<priority>0.5</priority>
  30:<mobile:mobile/>
  31:</url>
  32:<url>
  33:<loc>http://m.ppedv.at/kontakt</loc>
  34:<lastmod>2013-05-14</lastmod>
  35:<changefreq>monthly</changefreq>
  36:<priority>0.5</priority>
  37:<mobile:mobile/>
  38:</url>
  39:<url>
  40:<loc>http://m.ppedv.at/S/4,21</loc>
  41:<lastmod>2013-05-14</lastmod>
  42:<changefreq>monthly</changefreq>
  43:<priority>0.5</priority>
  44:<mobile:mobile/>
  45:</url>
  46:</urlset>

Dann werden per VB.NET und XML Literals ( eine wunderbare Funktion die es in C# nicht gibt) neue Nodes anhand einer Tabelle hinzugefügt. Das ganze in einer HTML entkernten ASPX Seite.

   1:Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
   2:Dim x As XDocument = XDocument.Load(Server.MapPath("~/app_data/sitemap.xml"))
   3:        x.AddAnnotation(SaveOptions.OmitDuplicateNamespaces)
   4: 
   5: 
   6:Dim pp As ppcompanyEntities = New ppcompanyEntities
   7:
   8:Dim query = pp.SEMINARE.Where(Function(s) s.isActive )
   9:For Each s In query
  10: Dim n = <url>
  11:                        <loc>http://m.ppedv.at/d/<%= s.SEID %></loc>
  12:                        <lastmod><%= Date.Now.ToString("yyyy-MM-dd") %></lastmod>
  13:                        <changefreq>daily</changefreq>
  14:                        <priority>0.5</priority>
  15:                        <mobile:mobile/>
  16:                    </url>
  17:            x.<urlset>.First.Add(n)
  18:Next
  19: 
  20: 
  21:        Response.Write(x.ToString)
  22: 
  23: 
  24:End Sub

Allerdings sind im urlset zwei Namensräume deklariert. Um den Code (hier speziell mobile: ) überhaupt kompilieren zu können braucht es passende Imports.

   1:Imports <xmlns:mobile="http://www.google.com/schemas/sitemap-mobile/1.0">
   2:Imports <xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">

Danach werden diese XML Namensräume sozusagen doppelt und mehrfach aber bei jedem URL Element eingefügt. Zeile 3 verhindert dieses wiederum.

Dann bleibt nur noch abzuwarten, wann königliche Hoheit, mein Gnadenersuch um wohlwollende Aufnahme in den Index auch erhört.

Wer das komplette XML File benötigt, kann es natürlich unter http://m.ppedv.at/sitemap.xml abrufen.

Tags:

.Net | SEO | XML

JQuery Mobile Ajax Callbacks

by Hannes Preishuber13. Mai 2013 21:13

ASP.NET Websites und das ASP.NET Scriptmanager Steuerelement können unter Umständen in Konflikt geraten. Grund ist, das Jquery Mobile automatisch clientseitige redirects per XMLHTTPRequest nachlädt.

image

Der Vorteil dieses Callbacks ist, das man dann den Seitenwechsel wunderbar animieren kann. Es reicht ein simples Attributim Hyperlink  und dann wird geslided  oder gefaded beim Übergang auf die nächste ASPX oder HTML Seite.

   1:<ul data-role="listview">
   2:<li><a href="WebForm22a" data-transition="slide">test</a></li>
   3:</ul>

slides

Wie erwähnt kann das aber auch Störungen hervorrufen. Um das Standard verhalten zu erzeugen, muss vor dem Laden des JQuery Mobile Scripts, AjaxEnabled auf false gesetzt werden.

   1: <script src="Scripts/jquery-1.8.2.min.js"></script>
   2: <script>$(document).on("mobileinit", function () { $.mobile.ajaxEnabled = false; }); </script>
   3: <script src="Scripts/jquery.mobile-1.3.0.js"></script>

image

Natürlich gibt es dann keine animierten Transitions mehr.

Tags:

ASP.NET | JavaScript | JQuery

CDN mit ASP.NET Scriptmanager

by Hannes Preishuber1. Mai 2013 07:59

Performance, Performance hallt es durch die Hallen. Wenn man sich allerdings mit Fiddler die Details von Websites und Services ansieht wird man eher Waste, Waste, Waste rufen. Mich wundert es das die Grünen nicht schon lange eine Steuer auf Prozessortakte oder DSL Bits erheben wollen. Verbraucht alles Energieund erzeugt CO2.

Die beiden einfachsten Maßnahmen für einen Web Developer sind httpcompression und CDN (Content Delivery Network).  Bei CDN wird ein Konzept der Shared Ressources gefahren. Eine Resource die zwei Websites brauchen wird geteilt und so nur einmal in den Browser Cache geladen. Wenn man dazu eine öffentliche URL nimmt und alle Menschen dies tun reduziert das nochmals Rechenleistung, eventuell Bandbreite durch Caching. Solche CND Dienste bieten Google und Microsoft. Wenn die Website also nun die sehr verbreitete JQuery Java Script Library verwendet wird sie von einem CDN Server geladen. Dies geschieht meist ein wenig schneller, weil diese Server sehr gut angebunden sind. Wesentlich relevanter ist aber wenn der Benutzer eine andere Website aufruft die ebenfalls Jquery, logischerweise mit der gleichen CDN Referenz, verwendet. Dann wird gar nichts geladen, die Scripte kommen aus dem Browser Cache.

In ASP.NET gibt es den ScriptManager der das Management übernimmt. Zunächst wird eine mini JS Datei erzeugt mit dem Namen hannes.js.

   1:window.Hannes = (function( ) {
   2: 
   3:return "hannes";
   4:    })

Visual Studio kann auch die minimierte Versionen erzeugen und vor allem aktuell halten. Rechtclick auf js, Webtools, minifiy JS.

image

Wenn man nun in hannes.js eine Code Änderung vornimmt, wird die min Datei automatisch geändert.

Um diese Dateien einzubinden wird das ASP.NET Scriptmanager Control eingefügt. In der Praxis vermutlich in die Masterpage.

   1:<asp:ScriptManager ID="ScriptManager1" runat="server" EnableCdn="true" 
EnableCdnFallback="true"
   2: AjaxFrameworkMode="Disabled">
   3: <Scripts>
   4: <asp:ScriptReference Name="hannes" />
   5: 
   6: </Scripts>
   7:</asp:ScriptManager>
   8: 
   9:<div id="hannesdiv">
  10:</div>
  11:<script>
  12:            document.getElementById("hannesdiv").innerText = window.Hannes();
  13:</script>

Mit dem Attribut AjaxFrameworksMode wird verhindert das einige Microsoft Scripte (Stichwort Webbundle) geladen werden, die wir hier nicht brauchen. Relevant sind die beiden anderen Attribute mit CDN.

Wie im Code zu sehen ist wird das Script per Namen und nicht per Dateinamen referenziert (was auch möglich ist für klassisches JavaScript einbinden).

Die Script Referenz Hannes muss als Ressourcemapping definiert werden. Dazu erfinden wir ein eigenes CDN auf einem unser WebServerzu Demozwecken. Es werden Referenzen zur Debugversion  (web.config debug=true), lokalen Fallback Version und zum ppedv CDN definiert. Der Ausdruck LoadSuccessExpression wird später verwendet um den Fallback im Browser zu realisieren (Achtung Case Sensitiv)

   1: Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
   2:Dim Mapping = ScriptManager.ScriptResourceMapping
   3:        Mapping.AddDefinition("hannes", New ScriptResourceDefinition With
   4:        {
   5:            .Path = "~/Scripts/hannes.min.js",
   6:            .DebugPath = "~/Scripts/hannes.js",
   7:            .CdnPath = "http://www.ppedv.at/scripts/hannes.min.js",
   8:            .CdnDebugPath = "http://www.ppedv.at/scripts/hannes.js",
   9:            .CdnSupportsSecureConnection = True,
  10:                .LoadSuccessExpression = "window.Hannes"
  11:        })
  12: 
  13:End Sub

Im Praxistest wird der Request von meinem lokalen Computer auf den IIS Express durchgeführt. Im ersten Versuch mit Wlan im zweiten ohne Internet Verbindung.

image

Der Fallback greift dann auf das lokale Script zurück, das hier kleiner erscheint. Der Grund ist, das am ppedv.at IIS 8 offensichtlich HTTP Compression für die Extension JS (noch) nicht aktiviert ist.

Im Browser HTML Quellcode kann man dann erkennen wie das funktioniert und sieht den alten Bekannten aus LoadSuccessExpression wieder.

   1:<script src="http://www.ppedv.at/scripts/hannes.js" type="text/javascript"></script>
   2:<script type="text/javascript">
   3://<![CDATA[
   4:(window.Hannes)||document.write('<script type="text/javascript" src="Scripts/hannes.js"><\/script>');//]]>
   5:</script>

Im echten Web Projekt wird man dann allerdings häufiger Script Referenzen auf Jquery und co finden. Einige Bundles hat Microsoft schon vorkonfiguriert.

Tags:

ASP.NET | JavaScript | HTML

Listview forward Paging für mobile

by Hannes Preishuber27. April 2013 21:07

In mobilen Clients wird gerne eine Scrollbare Liste angezeigt, die der Benutzer mit einem Button am Boden erweitern kann. Bei jedem Click wird die Liste länger und länger. Als Beispiel die Suche nach Bahn oder Flug. Alle Flüge ab 08:00, dann werden 10  angezeigt. Mit click auf [weitere] kommen dann noch 10 hinzu usw.

Um das Layout zu erstellen, wird eine entkernte ASPX Seite erstellt, die dann einfach die TR und TDs liefert passend zum Paging. Dies ist damit die Layout Template Page.

   1:<%@ Page Language="vb" AutoEventWireup="false" 
CodeBehind="WebForm20.aspx.vb" Inherits="WebApplication2.WebForm20" %>
   2: 
   3:<asp:listview id="ListView1" runat="server" selectmethod="loadData" 
itemtype="WebApplication2.Customers">
   4:<ItemTemplate>
   5:<tr>
   6: <td><%#Item.Customer_ID%></td>
   7: <td><%#Item.Company_Name%></td>
   8: <td><%#Item.Country%></td>
   9: <td><%#Item.Address%></td>
  10:</tr>
  11:</ItemTemplate>
  12:</asp:listview>

Damit der Compiler das ohne Form Element schluckt muss man eine Methode überladen. Für das Paging wird ein Querystring verwendet und dann per LINQ gefiltert und per ASP.NET modelbinding (ab 4.5) gebunden.

   1:Public Class WebForm20
   2:Inherits System.Web.UI.Page
   3:Public Overrides Sub VerifyRenderingInServerForm(ByVal control As Control)
   4:Return
   5:End Sub
   6: 
   7:Public Function loadData(<QueryString> ByVal p As String) As IQueryable(Of Customers)
   8:Dim nw As New NorthwindEntities1
   9:Dim query = nw.Customers.OrderBy(Function(c) c.Customer_ID).Skip(p * 5).Take(5)
  10:Return query.AsQueryable
  11:End Function
  12:End Class

Nun wird die eigentliche ASPX Seite erstellt. In dieser wird dann der HTMLTable Kopf Bereich angelegt. Das ganze ist JQuery Mobile ready, so das man auch responsive mobile Web Pages erstellen kann um verschiedene Devices zu adressieren.

   1:<form id="form1" runat="server" data-role="page">
   2:<table id="GridView1" >
   3: <thead>
   4: <tr>
   5: <th data-priority="4">Customer_ID</th>
   6: <th data-priority="1">Company_Name</th>
   7: <th data-priority="2">Country</th>
   8: <th data-priority="3">Adress</th>
   9: </tr>
  10: </thead>
  11: <tbody>
  12: </tbody>
  13:</table>
  14:<a href="#" onclick="loadmeins()" data-role="button">mehr</a>

Per Ajax Callback wird die Template Page aufgerufen und der erhaltene TR String an die bestehende Tabelle angefügt

   1:function loadmeins() {
   2:            $.ajax({
   3:                type: "GET",
   4:                url: "WebForm20.aspx?p=" + page,
   5:                success: function (result) {
   6:                    $('#GridView1 tbody').append(result);
   7:                    page++;
   8:                }
   9:            });
  10:        }
  11:var page = 0;
  12:        loadmeins();

Der Benutzer kann nun mehr drücken, bis das LINQ Statement keine Daten mehr liefert (und darüber hinaus)

image

Im Vergleich zu meiner anderen Lösungwerden nun weniger als die Hälfte an Daten übertragen. Dazu kommt, man auch das ASP.NET Page Caching Feature verwenden kann.

Tags:

ASP.NET | Ajax | HTML | JQuery | JScript | JavaScript | Web

ASP.net Gridview Forward Only Paging

by Hannes Preishuber27. April 2013 19:41

Erinnern Sie sich noch an “Frames sind böse”? Oder HTML Layout Tabellen sind pfui. Dabei sind <table> Element immer noch völlig OK wenn es um die Darstellung von Daten in Tabellen geht. Streng genommen sind sie sogar erste Wahl, da die Struktur z.B. von Lesegeräten für Sehbehinderte ausgewertet werden kann. 

GirdView Bäh oder Super?

Eine HTML Tabelle sollte heute so aussehen. Ein Thead und tbody Element und die Header Spalten mit th.

   1:<div>
   2:<table cellspacing="0"id="GridView1" style="border-style:None;border-collapse:collapse;">
   3:<thead>
   4: <tr>
   5: <th scope="col">Customer_ID</th><th scope="col">Company_Name</th>
<
th scope="col">Contact_Name</th><th scope="col">Postal_Code</th>
   6: </tr>
   7:</thead><tbody>
   8: <tr>
   9: <td>ALFKI</td><td>Alfreds Futterkiste</td><td>Maria Anders</td><td>12209</td>
  10: </tr><tr>
  11: <td>ANATR</td><td>Ana Trujillo Emparedados y helados</td><td>Ana Trujillo</td>
<
td>05021</td>
  12: </tr><tr>
  13: <td>ANTON</td><td>Antonio Moreno Taquer&#237;a</td><td>Antonio Moreno</td>
<
td>05023</td>
  14: </tr><tr>
  15: <td>AROUT</td><td>Around the Horn</td><td>Thomas Hardy</td><td>WA1 1DP</td>
  16: </tr><tr>
  17: <td>BERGS</td><td>Berglunds snabbk&#246;p</td><td>Christina Berglund</td>
<
td>S-958 22</td>
  18: </tr>
  19:</tbody>
  20:</table>
  21:</div>
  22: 

Man wird es kaum glauben. Obiges HTML wird so vom ASP.NET Gridview Control erzeugt. Einen Haken gibt es, um das Rendering des THEAD und TBODY  zu erzwingen muss man im Code zb Page_Load das Attribut  setzen GridView1.HeaderRow.TableSection = TableRowSection.TableHeader

Das GridView wird per ASP.NET Model Binding an die Northwind Customers gebunden

   1:<asp:GridView ID="GridView1" runat="server" SelectMethod="loadData" AutoGenerateColumns="false"
   2:ShowHeaderWhenEmpty="true" BorderStyle="None"ClientIDMode="Static"Showheader="true"
   3:EmptyDataText="empty" GridLines="None" ViewStateMode="Disabled">
   4:<Columns>
   5:<asp:BoundField DataField="Customer_ID"HeaderText="Customer_ID" ReadOnly="True"/>
   6:<asp:BoundField DataField="Company_Name" HeaderText="Company_Name" ReadOnly="True"/>
   7:<asp:BoundField DataField="Contact_Name" HeaderText="Contact_Name" ReadOnly="True"/>
   8:<asp:BoundField DataField="Postal_Code" HeaderText="Postal_Code" ReadOnly="True" />
   9:</Columns>
  10: 
  11:</asp:GridView>

Erster Checkpoint ist also bestanden. Das Gridview Steuerelement erzeugt sauberen HMTL 5 Code. Einzig ein seltsames DIV liegt noch außen rum. Ich kann also das Gridview als Server Seitiges Layout Template benutzen.

Teil 2 meiner Idee ist, für das Paging immer fünf Datensätze im Gridview anzeigen zu lassen und nur den Table Part per RenderControl am Server erzeugen zu lassen. Ein kleines Stück JavaScript soll dann eine Methode am Server aufrufen und die pure <TABLE><TR><TD> .. Sequenz einfach unten an die bestehende Tabelle anhängen.  Die Server Methode kann man per miniService in die Page per <WebMethod> einbetten. Leider liefert diese nur SOAP oder JSON. Die wunderbare native HTML Code Anweisung muss also in ein JSON serialsiert und am Client wieder deserialisiert werden. Ohne diesen Overhead (an dem ich später noch feile) wird dieser Ansatz wesentlich effizienter sein als ein Web Api, Knockout und HTML Binding Ansatz. Außerdem muss man dafür ein ganz eigenes Userinterface und Service bauen. Ziel soll es aber sein so nah wie möglich an Webforms dran zu bleiben.

Allerdings und nun folgen weitere Haken und Ösen ist das mit dem RenderControl weit weniger trivial als ich das in Erinnerung hatte. Erstens muss man das Gridview in ein UserControl packen. Außerdem muss das Pagegerüst außen rum  liegen. Also erst Page bauen, Control laden, rendern und am ende ein wenig überflüssigen HTML wieder wegschnippeln.

   1:  <WebMethod()>
   2:Public Shared Function getTable(seite As Integer) As String
   3:Dim p As New basepage
   4:Dim Grid1 As myGrid = DirectCast(p.LoadControl("myGrid.ascx"), myGrid)
   5:        Grid1.pageNumber = seite
   6:        Grid1.DataBind()
   7:Dim sw As System.IO.StringWriter = New System.IO.StringWriter()
   8:Dim hw As System.Web.UI.HtmlTextWriter = New HtmlTextWriter(sw)
   9:        Grid1.RenderControl(hw)
  10:Dim xml As String = sw.ToString()
  11:Dim s1 = xml.IndexOf("<tr>")
  12:Dim s2 = xml.IndexOf("</table")
  13:Return xml.Substring(s1, s2 - s1)
  14:End Function

Wer genau hinsieht, wird bemerken das ich kein Page verwende, sondern basepage. Dies um den erzeugten HTML Code vorab schon zu minimieren, weil eigentlich wäre d auch noch FORM nötig.

   1:Public Class basepage
   2:    Inherits Page
   3: 
   4:    Public Overrides Sub VerifyRenderingInServerForm(ByVal control As Control)
   5:        Return
   6:    End Sub
   7:End Class

Geht auch mit Page aber muss dann im Nachgang mehr HTML Code beschnitten werden. Das erscheint mir unsinnig.

Um die PageMethod aufzurufen, verwende ich JQuery.  Wenn man die PageMethod mit einem ASP.NET Scriptmanager referenziert, geht's auch mit dem erzeugten Proxy bzw nur einer Zeile Code

PageMethods.getTable

Wie gesagt ich verwende Jquery, ein wenig Paging Logik am Client für den Seitenzähler und einen “ich will mehr” Hyperlink. Weil mein GridView ClientIDMode Static gesetzt ist, kann man sich auch auf die generierte ClientID 100%tig verlassen und dann einfach den erhaltenen <Table> Wust anhängen.

   1:<script>
   2: function loadmeins() {
   3: var p = "{seite:" + page + "}";
   4:                $.ajax({
   5:                    type: "POST",
   6:                    url: "WebForm19.aspx/getTable",
   7:                    contentType: "application/json; charset=utf-8",
   8:                    data: p,
   9:                    dataType: "json",
  10:                    success: function (result) {
  11: 
  12:                        $('#GridView1 tbody').append(result.d);
  13:                        page++;
  14:                    }
  15:                });
  16:            }
  17: var page = 1;
  18: 
  19:</script>
  20:<uc1:myGrid ID="myGrid1" runat="server" />
  21:<a href="#" onclick="loadmeins()">mehr</a>

Das User Control das als Layout Container für das Gridview dient brauch noch ein wenig, ganz wenig, Code Logik um das Paging abzubilden und den Header zu unterdrücken.

   1: Public Property pageNumber As Integer
   2:Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
   3:        GridView1.HeaderRow.TableSection = TableRowSection.TableHeader
   4:End Sub
   5:Public Function loadData() As IQueryable(Of Customers)
   6:If pageNumber > 0 Then
   7:            GridView1.ShowHeader = False
   8:End If
   9:Dim nw As New NorthwindEntities1
  10:Dim query = nw.Customers.OrderBy(Function(c) c.Customer_ID).Skip(pageNumber * 5).Take(5)
  11:Return query.AsQueryable
  12:End Function

Am Ende sieht das genauso aus wie am Anfang geplant.

forwardpaging

Obwohl es mit relativ wenig Aufwand möglich war mit dem ASP.NET Gridview ein Vorwärts Blättern zu realisieren, fühlt es sich seltsam an. Auch das verpacken in JSon gefällt mir nicht. Darüberhinaus ist es für ein einfaches Szenario mit anderen Controls wie Repeater oder Listview einfacher eine saubere und passende HTML Tabelle zu rendern.

Wer Tipps hat was man besser machen kann, soll wie immer hier ein Kommentar hinterlassen.

Tags:

ASP.NET | JavaScript | VB

ASP.NET ASMX Services mit Windows 8 Store APP

by Hannes Preishuber26. April 2013 19:53

In meiner aktuellen Windows Developer Schulung wollte ich einen ASP.NET Webservice aufrufen. Dabei sollte per JSON und nicht per SOAP gearbeitet werden. Was in JavaScript ganz einfach geht, hat eine kleine Überraschung für mich bereit gehalten. Regelmäßige Leser meines Blogs werden erkennen mit C# und nicht VB.net.

ASP.NET Web Services gibt es seit der Version 1. Seit einiger Zeit kann man damit auch Json generieren und seit mir nicht bekannter Zeit in einem ganz speziellen Format.

Der Service nutzt die Northwind Customers Tabelle per EF.

   1:  [ScriptService]
   2:public class WebService1 : System.Web.Services.WebService
   3:    {
   4:        [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
   5:        [WebMethod]
   6:public List<Customers> Kunden()
   7:        {
   8:            var nw = new NorthwindEntities2();
   9: return nw.Customers.ToList();
  10:
  11:        }
  12:    }

Für den Aufruf des Services gibt man die url mit Methodennamen an also webservice1.asmx/Kunden. Dabei muss aber beim Request im HTTP Header der Content Type application/json angeben sein. Um den Service zu testen kann man Fiddler verwenden.

image

ASMX Services akzeptieren seit einiger Zeit nur ein HTTP Post. Wenn man das ändern möchte kann man im Methode Attribut WebMethod des Services dies angeben.

Der JSON Repsonse hat allerdings am Anfang ein d: im Stream.

image

Das ist kein Zufall sondern Absicht um ein bestimmtes XSS Problem zu umgehen. Jedenfalls kann so nicht direkt mit DataContractJSONSerializer deserialsiert werden. Man könnte nun den String Parsen und damit anpassen, ich wähle allerdings JSON.NET weil der Code damit logischer erscheint.

Um Die Datenklasse im Windows 8 Store APP (also METRO oder WinRT) zu erzeugen kopiere ich den Json Source komplett in die Zwischenablage (hier nur ein Auszug)

   1:{"d":[{"__type":"WebApplication1.Customers","Customer_ID":"ALFKI","Company_Name":"Alfreds 
Futterkiste"
,"Contact_Name":"Maria Anders","Contact_Title":"Sales Representative",
"Address":"Obere Str. 57","City":"Berlin","Region":null,"Postal_Code":"12209","Country":"Germany",
"Phone":"030-0074321","Fax":"030-0076545","EntityState":2,"EntityKey":{"EntitySetName":"Customers",
"EntityContainerName":"NorthwindEntities2","EntityKeyValues":[{"Key":"Customer_ID","Value":"ALFKI"}],
"IsTemporary":false}},{"__type":"WebApplication1.Customers","Customer_ID":"ANATR",
"Company_Name":"Ana Trujillo Emparedados y helados","Contact_Name":"Ana Trujillo"
,"Contact_Title":"Owner","Address":"Avda. de la Constitución 2222","City":"México D.F.",
"Region":null,"Postal_Code":"05021","Country":"Mexico","Phone":"(5) 555-4729",
"Fax":"(5) 555-3745","EntityState":2,"EntityKey":{"EntitySetName":"Customers",
"EntityContainerName":"NorthwindEntities2","EntityKeyValues":[{"Key":"Customer_ID","Value":"ANATR"}],
"IsTemporary":false}},{"__type":"WebApplication1.Customers","Customer_ID":"ANTON",
"Company_Name":"Antonio Moreno Taquería","Contact_Name":"Antonio Moreno",
"Contact_Title":"Owner","Address":"Mataderos 2312","City":"México D.F.","Region":null,"

Wenn man den  Code schon in der Zwischenablage hat, kann man auch per Visual Studio Paste JSON as Class die Klasse erzeugen lassen.

image

Um den Traffic belauschen zu können habe ich fiddler zwischengeschaltet. Dann muss der Webservice im Code mit der speziellen Fiddler Adresse angesprochen werden. Dann per httpclient ein Post auslösen.

Das D wird als JsonObject extrahiert und daraus dann einen Liste erstellt.

   1:private async void Button_Click(object sender, RoutedEventArgs e)
   2:        {
   3:            var http = new HttpClient();
   4:            HttpContent cnt = new StringContent("");
   5:            cnt.Headers.ContentType = new MediaTypeHeaderValue("application/json");
   6:            var r = await http.PostAsync(
new Uri("http://localhost.fiddler:26826/WebService1.asmx/Kunden", UriKind.Absolute), cnt);
   7:            var js = await r.Content.ReadAsStringAsync();
   8:            JObject jsonobj = (JObject)JsonConvert.DeserializeObject(js);
   9:            var x = JsonConvert.DeserializeObject<List<Customers>>(jsonobj["d"].ToString());
  10:            grid1.ItemsSource = x.ToList();
  11:        }

Tags:

ASP.NET | C#

mobile Paging mit ASP.NET Webforms

by Hannes Preishuber24. April 2013 08:23

Wer mehr Daten hat als auf den Bildschirm passen, verwendet gerne Paging in Zusammenarbeit mit  einem Datagrid.  Das ist sowohl aus Performance als auch Useability Sicht bei mobilen Clients nicht optimal. Ein Smartphone hat naturgemäß einen kleinen Screen.

Der User soll am besten,direkt die Daten sehen, die er braucht, oder wenigstens mit möglichst wenig Clicks oder Gesten dorthin kommen. Dabei erweist sich numerisches Paging oder der Next Prev Button als umständlich. Eine mobile Anzeigefläche ist recht klein und kann nur virtuell erweitert werden. Der Benutzer  gewohnt nach unten mit 2-3 Wischgesten zu scrollen. Nach rechts kann ebenso gewischt werden oder per Navigationshilfe, einem Pager.

Die im Seminar der ppedv finden an den rund elf Schulungsstandorten statt. Die Anzahl der Termine pro Monat variiert, übersteigt aber niemals dreißig. Folglich ergibt sich im Paperdesign folgende Navigation.

image

Verwendet wird in der ppedv WebApp ein selbstgeschriebener Pager, der die Termine pro Monat anzeigt. Der Benutzer sieht dann jeweils eine Liste mit 0 bis ca max 15 Einträgen, die einfach zu scrollen ist.

image

Der selbstgebaute Pager ist super simpel. Zur besseren Nachvollziehbarkeit  hier statt dem Kursdaten, mit der Customers Tabelle aus der Nordwind Datenbank. Das Paging findet mit dem ersten Buchstaben statt, bzw. einem Buchstaben Bereich. Anstatt eines Postbacks wird ein normaler Querystring verwendet. Suchmaschinen können zur Freude des SEO noch die ganze Datenmenge indizieren. Für die mobile Darstellung wird mit Query Mobile ein client seitiges JavaScript Framework verwendet. Dieses nutzt die data-* Attribute von HTML 5 um per CSS das Aussehen zu manipulieren. Die Page selber muss mit dem Attribut data-role=”page” versehen werden, das man in das Form Element legen kann.

   1:<div >
   2:<a href="?p=a,f" data-role="button" data-inline="true" data-mini="true">a-f</a>
   3:<a href="?p=g,m" data-role="button" data-inline="true" data-mini="true">g-m</a>
   4:<a href="?p=n,s" data-role="button" data-inline="true" data-mini="true">n-s</a>
   5:<a href="?p=t,z" data-role="button" data-inline="true" data-mini="true">t-z</a>
   6: </div>

Ja, das ist der Pager. Das ganze in einem UserControl (ascx), würde das ganze eleganter und wiederverwertbar machen.

Die Attribute:

  • data-role=Button erzeugt das aussehen eines Buttons
  • data-inline reduziert den Button auf die notwendige größe. Ohne nutzt er die komplette breite
  • data-mini macht einen kleineren Button

Zur Listendarstellung wird das ListView Control verwendet. Nach meiner Ansicht das mächtigste und modernste ASP.NET Server Steuerelement. Ganz wichtig ist die ASP.NET 4.5 Funktion Model Binding. Mit SelectMethod wird die Methode angegeben die die Liste liefert. ItemType ist eigentlich nicht nötig, erlaubt aber statt Eval() eine vereinfachte Syntax, mit Item., die dabei auch von Intellisense noch unterstützt wird. Kurs gesagt, strongly typed.

   1: <asp:ListView ID="ListView1" runat="server" 
SelectMethod="loadData" ItemType="WebApplication2.Customers" >
   2:<ItemTemplate>
   3: <li><%#Item.Company_Name%></li>
   4:</ItemTemplate>
   5:<LayoutTemplate>
   6:<ul data-role="listview">
   7: <asp:PlaceHolder ID="itemPlaceholder" runat="server"></asp:PlaceHolder>
   8:</ul>
   9:</LayoutTemplate>
  10:</asp:ListView>

Der Jquery mobile (JQM) Anteil beschränkt sich auf das Attribut data-role=Listview. JQM benötigt aber eine HTML unorderdList aus <UL> und <LI> Elementen. Für  Daten in Tabellenstruktur mit <TR> <TD> usw. gibt es ein anderes Attibut data-role=”table”. Obwohl die data-* Attribute keine Web Forms Attribute sind, werden sie zur Laufzeit sauber als HTML gerendert.

Im Page Code ( manche sagen auch Codebehind)  liefert uns ein sehr schlanke Methode Daten aus einem Entity Framwork Model. Ginge natürlich auch mit SQLCommand und Datareader, braucht nur ca. 15 Zeilen Code mehr, für Datenbank Zugriff und generische Liste mit LINQ bauen.

   1: Public Function loadData(<QueryString> ByVal p As String) As IQueryable(Of Customers)
   2:If p = "" Then p = "A,B"
   3:Dim b = Split(p, ",")
   4:Dim nw As New NorthwindEntities1
   5:Dim start = b(0)
   6:Dim ende = b(1)
   7:Dim query = nw.Customers.Where(Function(c) c.Company_Name.Substring(0, 1) >= 
start And c.Company_Name.Substring(0, 1) <= ende).OrderBy(Function(o) o.Company_Name).AsQueryable
   8:Return query
   9: End Function

Die Innereien der Methode benötigen kaum Erklärung (wenn doch, hier als Kommentar fragen). In der Methodensignatur wird, mit ein wenig Magie, der Querystring per Attribut der Variablen p zugewiesen. Da ich dabei einen Bereich benötige, werden die beiden Werte einfach per Komma getrennt übergeben. Natürlich könnte man auch min max in zwei Querystring Parametern angeben, ist aber dann weniger flexibel.

Wenn man nicht auf Querystrings steht, kann mit Hilfe der neuen ASP.NET FriendlyUrl Erweiterung auch mit Urls in der Form \a,b und \b,c gearbeitet werden. In der Methode LoadData kommt das entsprechende Attribut zum Einsatz. Um den Parameter im Falle von mehreren zu identifizieren zu können, muss noch ein Index angegeben werden.

   1:(<FriendlyUrlSegments(0)> p As String)

Das Ergebnis im IPhone Simulator (aus WebMatrix)

image

In einem meiner nächsten Blogs werde ich auf Paging nach unten eingehen.

Tags:

ASP.NET | HTML | SEO | JQuery | JavaScript

ASP.NET TextBox Reloaded

by Hannes Preishuber21. April 2013 20:42

Immer wieder stoße ich auf Vorurteile bezüglich Webforms. Einmal abgesehen davon, das ein INPUT Element durch einfachen Zusatz von runat=”server” zum HTML Server Element wird, kann auch ein Webforms Element “sauberen” HTML5 Code. 

Ein Beispiel sind die neuen Input Type Attribute mit Werten wie Text, Multiline, Password, Color, Date, DateTime, DateTimeLocal, Email, Month, Number, Range, Search, Phone, Time, Url, Week. Dabei kommen auch zusätzliche Attribute wie hier min max in Frage

   1:<input id="Text1" type="range" min="0" max="10" runat="server" />

image

Mobile Browser können, müssen aber nicht, passende On Screen Keyboards einblenden.

Die ASP.NET Textbox bildet das mit 4.5 über das Attribut TextMode ab.

   1:<asp:TextBox ID="TextBox1" TextMode="Date" runat="server" >

Chrome macht da auch einen schönen Kalender draus (der IE nicht)

image

Für den Einsatz von Javascript wird oft die ID eines HTML DOM Elements benötigt. Seit ASP.NET 4 existiert das Attribut ClientIDMode. Wenn man dies auf Static setzt wird die ID ident im HTML gerendert.

Visual Studio ist so nett und weist den Entwickler auf etwaige ID Konflikte hin.

image

Der IIS bzw. ASP.NET hat aber zur Laufzeit keine Probleme damit.

Ein weiteres neues HTML Attribut ist Pattern mit dem anhand von Regulären Ausdrücken Eingaben validiert werden können. Manche Browser nutzen dies auch für die Auswahl des Onscreen Keyboards. Solche Attribute nimmt die Textbox an, obwohl Visual Studio 2012 IntelliSense dies nicht vorschlägt.

   1: <asp:TextBox ID="TextBox1" TextMode="Date" runat="server" ClientIDMode="Static"pattern="[0-9]*"/>
   2:im Browser
   3: <input name="TextBox1" type="date" id="TextBox1" pattern="[0-9]*" />

Tags:

ASP.NET | HTML

Migrating ASP.NET View nach 4.5

by Hannes Preishuber19. April 2013 08:39

In einer rund 8 Jahre alten Web Anwendung muss eine einzelne Page modernisiert werden. Die Webanwendung ist eine Website, also kann man direkt den Code im Code Behind ändern ohne den Rest der Anwendung zu zerstören. Der damaligen Auffassung von OOP folgend wurde mehrfach, teils inhaltslos, gekapselt (DLL, BLL). Die Datenlogik befindet sich in Stored Procedures, die in diesem Fall mindestens zwei Tabellen denormalisiert in einem ADO.NET Dataset bzw. Datatable durch die Schichten reicht. In der ASPX Page wurde ein Repeater eingesetzt, der mit Verzweigungslogik Header ein ausblendet. Im Codebehind befinden sich rund 180 Zeilen Eventlogik und Validierungscode, bzw. die Instanziierung der BLL.

Ein klassischer Fall von Brownfield Projekt, in dem die Veränderung  nur eines Feldes tagelange Arbeit nach sich ziehen kann. Lässt der Entwickler sich dazu hinreißen auch gleich aufzuräumen, werden schnell Monate daraus.

Die Ziele sind modernes UI (zb mit Filter) und so wenig wie möglich Aufwand.

Datasets sind obsolet

Mit .net 4.5 existiert ein LINQ 2 Dataset Provider. Um die 1:N Darstellung zu realisieren, wird mit LINQ die Sicht wieder gesplittet in Master und Client Daten. Da Dataset nicht streng typisiert sind, muss man die Felder über eine “Field” und “Feldname” Methode auslesen. Es existiert eine verkürzte Syntax in VB mit dem !, die hier im VB.NET Code zur Anwendung kommt.

Startpunkt ist die Extension Methode asEnumarable, die Datarow Linq typisch liefert. In diesem Fall wird mit anonymen Strukturen gearbeitet, so das man mit “Key” Schlüsselwort in Verbindung mit Distinct nur die einmaligen Datensätze bekommt. Sozusagen die Masteransicht.

   1:Dim query = From sem In ds.Tables(0).AsEnumerable
   2: 
   3:                  Order By If(rdDatum.Checked, sem!Termin, sem!Title)
   4: Select New With {Key .SEDETID = sem!SEDETID,
   5:                          .Title = sem!Title,
   6:                         .Ort = sem!Ort,
   7:                         .Dauer = sem!Dauer,
   8:                         .Termin = sem!Termin,
   9:                         .Name = sem!Name,
  10:                         .Unterlagen = sem!Unterlagen
  11:                        } Distinct

Repeater sind praktisch

Der HTML Part wurde von mir nahezu komplett gelöscht. Ziel war es klare UL und LI Strukturen im DOM zu bekommen, um diese einfach manipulieren zu können. So wurde ein Client Filter per JavaScript eingebaut. Außerdem kann man auch die LINQ Query am Server beeinflussen. Das ist eine wunderbare neue Funktion von Webforms Model Binding in ASP.NET 4.5. Der Radiobutton wird im obigen LINQ Statement berücksichtigt und beeinflusst die Sortierung.

Der erste Teil der ASPX Seite

   1:   filtern<input id="searchbox1" placeholder="Tippen" />
   2:<asp:RadioButton ID="rdDatum" runat="server" GroupName="eins" Text="Datum" 
AutoPostBack="true" />
   3:<asp:RadioButton ID="rdThema" runat="server" GroupName="eins" Text="Thema" 
Checked="true" AutoPostBack="true" />
   4: 
   5:<ul class="navlist">
   6: <asp:Repeater ID="rpSemBooked" runat="server" SelectMethod="rpSemBooked_GetData">

Die Methode in der Page “rp_SemBooked_GetData” enthält dann eigentlich nur das LINQ Statement und eine passende Signatur.

   1:Public Function rpSemBooked_GetData() As System.Collections.IEnumerable
   2:Dim query = From sem In ds.Tables(0).AsEnumerable
   3:       ...
   4:Return query

Das finde ich nur cool. Einfach klar und sogar noch mit eine wenig Designer Support. Steht einem ASP.NET MVC Ansatz in kaum was nach.

Master Detail oder Nested Repeaters

Repeater lassen sich einfach und beliebig tief verschachteln. Mein Vorgänger hat sich dafür die Databinding Events gekrallt um dem Client Repeater jeweils seine neue Bindung zuzuweisen auf die 1:N.

Ich habe mich entschieden ein Hidden Field als Träger des Keys im Master Repeater unterzubringen.

   1:<ul>
   2:<asp:Repeater ID="rpSemBooked" runat="server" SelectMethod="rpSemBooked_GetData">
   3:<ItemTemplate>
   4:<asp:HiddenField runat="server" ID="hID" Value='<%#Eval("SEDETID")%> />
   5: <ul>
   6: <h3><%#Eval("Title")%> </h3>
   7:        .....
   8: <asp:Repeater ID="rpTln" runat="server" SelectMethod="rpTln_GetData">
   9: <ItemTemplate>
  10: <li>

In der Select Methode des Client Repeaters lässt sich mit einem simplen Attribut der ID Wert auslesen.

   1:Public Function rpTln_GetData(<Control()> hID As String) As System.Collections.IEnumerable
   2:Dim query = From sem In ds.Tables(0).AsEnumerable
   3:            Where sem!SEDETID = hID ...

Es gibt rund 10 mögliche Attribute für ID Quellen. Wichtig ist sicher Querystring, RouteData oder auch Session.

Nur der Vollständigkeit halber der JavaScript code (mit ein wenig JQuery) um im Browser zu filtern.

   1:   $('#searchbox1').keyup(function () {
   2: 
   3: var valThis = $(this).val().toLowerCase();
   4:            $('.navlist>ul').each(function () {
   5: var text = $(this).text().toLowerCase();
   6:                (text.indexOf(valThis) >= 0) ? $(this).show() : $(this).hide();
   7:            });
   8:        });

Dauer des Projekts waren rund 2h. Das Risiko sehr gering. Die Listendarstellung ist nun wesentlich schneller und bietet zwei neue Filter Funktionen am Webserver und am Client. Am Ende hat sich der benötigte VB.NET Programmiercode und der deklarative ASP.NET Teil fast halbiert.

Tags:

ASP.NET | JScript | Web | VB

About the author

Something about the author

Month List

Page List