IIS Express und FQDN

Mein aktueller Anwendungsfall einer ASP.NET Web-Anwendung benötigt statt dem üblichen localhost eine echte Domain als Namen. Wer aus Visual Studio eine Website startet, tut dies in der Regel mit IIS Express (früher Cassini Web Develeopment Server).

Dort wird ein zufälliger Port ausgewählt und in die universelle Konfiguration des IIS Express Web Servers in applicationhost.config eingetragen.

image

Den Speicherort der Datei findet man im Screenshot  des IIS Express (Task Bar – Notification Icons- Item- Rechtsklick). Um ein zweites Mapping einzutragen, wird diese Config Datei direkt per Notepad geöffnet. In den Bindings wird eine oder mehrere Bindungen aktiviert.

   1:    <bindings>
   2:  <binding protocol="http" bindingInformation="*:5376:localhost" />
   3:   <binding protocol="http" bindingInformation="*:80:ppedv.localtest.me" />
   4:  </bindings>

Die Adresse localtest.me zeigt immer auf die lokale localhost Adresse 127.0.0.1. und ist damit ein Trick eine echte Internet-Domain zu nutzen, ohne die Hosts-Datei oder schlimmeres zu beanspruchen. Port 80 ist nicht unbedingt erforderlich.

Wenn ein lokaler IIS installiert ist, fängt dieser per Universal Binding alle Domains auf der IP 127.0.0.1 ab. Auch ein Stoppen des www-Publishingdienst löst das Problem nicht. Erst wenn man einen Hostname im IIS Manager vorgibt, ist es anderen Websites möglich ein Binding durchzuführen.

image

Stolperstein #2 ist, dass Binden abseits von localhost auf IIS Express nur möglich ist, wenn IIS Express im Administrator Context läuft. Dazu muss Visual Studio als Administrator (rechte Maustaste runas Administrator) ausgeführt werden.

Im Ergebnis lauscht nun die Web App auf beiden URI

image

Facebook-Login in ASP.NET Webforms

Die Welt bleibt nicht stehen. Das Nutzungsverhalten von Websites ändert sich. Das durchaus bewährte ASP.NET Membership Provider System wird durch ASP.NET Identity abgelöst. Wer heute mit Visual Studio 2013 ein neues Web Projekt anlegt, findet die komplette Benutzerverwaltung voreingerichtet - basierend auf Microsoft.AspNet.Identity.

Das Modul wird in der Datei IdentityConfig aus dem Verzeichnis App_Start hochgefahren. Dort kann man auch die unsäglich strikte Passwort-Policy aufweichen.

   1:     manager.PasswordValidator = New PasswordValidator() With {
   2:            .RequiredLength = 1,
   3:            .RequireNonLetterOrDigit = False,
   4:            .RequireDigit = False,
   5:            .RequireLowercase = False,
   6:            .RequireUppercase = False
   7:          }

 

Die Struktur bzw. die Eigenschaften des Benutzers werden in der Klasse ApplicationUser der Datei IdentityModels vorgegeben. Entsprechend des Code First Paradigmas des Entity Frameworks und der Einstellung aus der Web.Config wird dann die Datenbank automatisch angelegt.

   1:  <connectionStrings>
   2:      <add name="DefaultConnection" 
connectionString="Data Source=(LocalDb)\v11.0;AttachDbFilename=
|DataDirectory|\aspnet-WebFormsIdentity-20140712075341.mdf;
Initial Catalog=aspnet-WebFormsIdentity-20140712075341;Integrated Security=True"
   3:        providerName="System.Data.SqlClient" />
   4:    </connectionStrings>

 

In der Datei StartUp.Auth.vb sind Methoden für Twitter, Google und Facebook vorkonfiguriert, aber auskommentiert.

   1:   app.UseFacebookAuthentication(
   2:   appId:=ConfigurationManager.AppSettings("FacebookId"),
   3:   appSecret:=ConfigurationManager.AppSettings("FacebookSecret"))

Die Authentication Methode erwartet zwei Parameter, die ID und das Secret. Anders als eine Benutzername-Passwort-Kombination ist diese sozusagen das Login einer Anwendung. Der Benutzer sieht diese Daten nicht und entsprechend macht es Sinn, diese in die Web.Config auch aus dem Code auszulagern.

Im nächsten Schritt muss der Entwickler eine App bei Facebook anlegen, um die Parameter ID und Secret zu generieren. Es wird also ein Facebook-Account benötigt. Einstiegspunkt ist das FB Developer Portal.

Nachdem die App per New App erstellt wurde, können die beiden Parameter aus dem Formular kopiert werden.

image

Wer jetzt loslegt, wird eine Fehlermeldung im Browser erhalten.

Die Anwendungseinstellungen lassen die angegebene URL nicht zu: Eine oder mehrere URLs sind in den Einstellungen der App nicht zugelassen. Sie müssen mit der Website-URL oder der Canvas-URL übereinstimmen, oder die Domain muss Subdomain einer der App-Domains sein.

Dazu muss man wissen, dass eine sogenannte 2-Legs-Authentifzierung auf Basis von OAuth2 zum Einsatz kommt. Im Kern übernimmt ein Provider – hier Facebook – die Anmeldung und reicht dann einen Zugangstoken an die aufrufende Website weiter. Dazu ist es aber nötig, Facebook die URL der aufrufenden Website mitzuteilen.

Die Einstellung wird im Developer Portal von Facebook in den Settings der App vorgenommen.

image

Die hier gewählte lokale URL ist natürlich nicht praxistauglich.

Der Login Dialog der ASP.NET Website erzeugt nun einen zusätzlichen Button für den Facebook-Login auf der rechten Seite.

image

Folgerichtig wird das Passwort in der Tabelle ASPNetUsers auch frei gelassen. Nur ein lokaler Benutzer kann auch ein Passwort besitzen, das per Hash verschlüsselt gespeichert wird.

image

Den zweitbesten per TSQL finden

Das passt ja fast zur Fussball-Weltmeisterschaft. Ein Teilnehmer einer ppedv Schulung schreibt mir:

“Ich habe da eine „knifflige“ Aufgabe in der Firma, wo ich mit meinem bescheidenen SQL-Wissen nach ein paar Stunden nicht mehr weiter komme. Ich kann's natürlich über Umwege lösen, glaube aber dass man das mit einem sql query oder sql query + stored procedure oder function auch zusammenbringt.”

Kurz zusammengefasst: eine SQL Abfrage im Microsoft SQL Server soll den zweiten Wert liefern. Die Frage war mir neu und mein SQL-Wissen auch ein wenig eingerostet - teilweise war es auf dem Stand von SQL 2000. Seit 2005 ist aber RowNum hinzugekommen und seit 2012 auch ein Offset-Kommando, um in Kombination mit z.B. TOP /Group By einfach einen Datensatz zu überspringen. So zunächst mein erster Gedanke.

Die Ausgangstabelle

   1:  CREATE TABLE [dbo].[KickiTest](
   2:      [ID] [int] IDENTITY(1,1) NOT NULL,
   3:      [Ergebnis] [bit] NULL,
   4:      [Datum] [datetime] NULL,
   5:      [Seriennummer] [int] NULL
   6:  ) ON [PRIMARY]

Die Daten

image

Abfrage: Für alle Geräte, deren Ergebnis positiv ist, der zweite Datensatz. Wenn dieser nicht vorhanden ist, wird der erste abgefragt. 

Die Lösung verwendet die generierte Zeilennummer in Kombination mit einem Zähler

   1:  WITH tmp  AS (SELECT ID, Ergebnis, Datum, Seriennummer,
   2:         anzahl= Count(seriennummer) OVER(PARTITION BY seriennummer) ,
   3:          ROW_NUMBER() OVER (PARTITION BY seriennummer 
ORDER BY seriennummer,datum) AS RowNum
   4:          FROM   KickiTest where ergebnis=1) 
   5:   
   6:   
   7:  SELECT ID, Ergebnis, Datum, Seriennummer,rownum,anzahl
   8:  from tmp
   9:  where (anzahl = 1) or (anzahl>1 and rownum=2) 

 

Freie Bilder ganz schön teuer

Nachdem ich gestern einen Blog-Eintrag gelesen habe, der sich mit der Verwendung von Gratis-Fotos auf Webseiten beschäftigt, kann ich nur raten: „Finger weg“.

Die ppedv AG hat seit Anfang 2011 zahlreiche Prozesse laufen, die sich u.a. im Bereich Wettbewerbsrecht abspielen. Dabei geht es pro Klage durchaus auch um hohe sechsstellige Beträge. Beispielhaft sei genannt: die strittige Verwendung von fünf Sternen als Indikator besonderer Qualität. Zeitgleich haben wir regelmäßig auch Verfahren mit eigentlich unbekannten Dritten aufgrund anonymer Hinweise, z.B. mahnte uns die Wettbewerbszentrale München wegen des Schulungskatalogs ab mit nachfolgendem Schlichtungsverfahren. Aktuell verdanken wir genauso einem Tipp Post von Rechtsanwalt Schlösser, der den Fotografen Kleinschmidt vertritt. Konkret haben wir auf einer sehr tiefliegenden Unterseite einen Papagei als etwas größeres Thumbnail abgebildet und damit die Rechte eines Künstlers verletzt.

Aus SEO-Gründen wurde das Bild umbenannt und aus Optimierungsgründen die EXIF-Informationen entfernt. Am Ende hatte es 7kb und war 150 x100 Pixel groß. Das Bild wurde vor über sieben Jahren in einem Foto-Portal erworben. Der Mitarbeiter, den es heute nicht mehr gibt, hat per Kreditkarte ein Credits Paket erworben und daraus unter anderem dieses Bild verwendet. Ohne entsprechendes Hintergrundwissen ist dieses Bild somit für niemanden auffindbar bzw. dem Fotografen zuzuordnen.

Die damaligen Lizenzbedingungen des Portals forderten die Nennung des Portals im Impressum als Quelle. Alles im grünen Bereich und wir haben das soweit auch dokumentiert.

Faktisch erwirbt man mit der Lizenz bestenfalls ein beschränktes Nutzungsrecht. Darüber hinaus hat der Fotograf das Recht als Urheber direkt beim Bild genannt zu werden. Das haben wir, alleine aus optischen Gründen, damals nicht getan und auch rechtlich nicht für nötig gehalten.

Der Anwalt möchte nun rund 1600€ im Vergleichsverfahren. 800 für den Fotograf und 800 für seinen Aufwand. Nicht ohne umfangreich zu erklären, wie schlecht es für uns aussieht. In der Regel gehen solche Verfahren auch negativ für den Beklagten aus. Der Kläger sucht sich ein für seine Ziele in der Rechtsprechung einschlägig bekanntes Gericht aus. Da das Foto im Internet abrufbar ist, ist der Tatort unbestimmt; dies ist bekannt als fliegender Gerichtsstand. Als konkretes Beispiel: Ein Mitglied aus der Community wird im Süden (Traunstein) verklagt, obwohl der Kläger aus dem Osten ist und der Beklagte aus dem Westen. Auch wir sind schon vom identen Gegner in Leipzig, Dresden, Frankfurt, Traunstein, München und Düsseldorf verklagt worden.

Das besonders perfide dabei ist, dass man sich davor nicht schützen kann. Selbst wer ein Foto kauft, kann nie sicher sein, dass es vom genannten Urheber stammt. Der muss nur mit seiner Digitalkamera in den Gerichtssaal spazieren und das Original vorzeigen. Man munkelt, dass es einige Fotografen und Anwälte gibt, die ihr Geschäftsmodell ausschließlich darauf aufbauen. Darüber hinaus gelten hier Aufbewahrung und Nachweisfristen, die sich am Urheberrecht orientieren. In unserem Fall betreiben wir über 60.000 einzelne Seiten, von denen wir nicht wissen, wer jede einzelne erstellt hat. Selbst wenn wir es wüssten und eine Agentur das durchgeführt hätte, befreit das nicht im Geringsten von den Schadensersatzansprüchen.

Mein Tipp: Finger weg von Fotoportalen, egal ob kostenlos oder bezahlt. Free kann ganz schön teuer werden. Am besten nur eigene Fotos verwenden oder einen Fotograf vor Ort beauftragen. Wer weitere Fragen dazu hat, kann mir gerne eine E-Mail senden.

ASP.NET Webforms Scaffolding

Code-Generatoren sehe ich sehr kritisch. Speziell dann, wenn es es sich um einen One-Way-Vorgang handelt. Genau dies bietet ASP.NET Scaffolding für MVC und seit kurzem auch für Webforms. Da dieser Wizard aber doch ein wenig Arbeit sparen kann, werfen wir einen Blick darauf. Aktuell wird nur C# unterstützt. VB.NET ist in Vorbereitung.

Der Webforms Scaffold Generator findet sich auf Github und ist Open Source. Er wird als Erweiterung in Visual Studio 2013 unter dem Namen Web Forms Scaffolding installiert. Dem Artikel liegt die Version 0.1 Beta 2 zugrunde (muss dabei leicht schmunzeln).

Als nächstes erzeugt man ein Model im Visual Studio Web Projekt. Dies kann per Entity Framework aus einer SQL-Datenbank geschehen oder einfach im Stile von Code First durch eine Klasse. Einzig zu beachten ist, dass dies nicht im Root-Verzeichnis, sondern am Besten im Model gespeichert wird. Es kommt sonst zu einem Namespace-Konflikt, da der Generator Model und View mit identem Namen wählt.

Per Dataannotations werden im Model Validierungsregeln deklariert.

   1:  namespace scaff7.Models
   2:  {
   3:      public class person
   4:      {
   5:          [Key]
   6:          public int id { get; set; }
   7:          [Required(ErrorMessage = "Muss was rein")]
   8:          [MaxLength(10, ErrorMessage = "zu lange")]
   9:          public String Name { get; set; }
  10:          [Display(Description = "geburtstag")]
  11:          public DateTime gebDat { get; set; }
  12:      }
  13:  }

Als nächstes wird per Rechtsclick ein Item vom Typ Scaffold hinzugefügt, zu Deutsch “neues Gerüstelement”.

image

Die Vorlage heißt “Webforms Pages using Entity Framework”.  Im kommenden Dialog werden Klasse und der vorhandene DBContext ausgewählt:

image

Mehr ist es nicht. Im Visual Studio Projekt Explorer erscheint ein Unterverzeichnis mit dem Namen der Klasse und einer Datei Default für Listendarstellung und eine Datei Edit für Anzeige und Bearbeiten und eine für den Insert.

image

Dahinter werden DynamicData Templates verwendet, die man nachträglich auch anpassen kann, um seine Designwünsche zu erfüllen. Selbst die Datenbank wird beim ersten Aufruf automatisch erstellt.

Das Layout basiert auf Bootstrap 3.

image

Sehr schick ist, dass auch bereits die Validierung berücksichtigt und visualisiert wird. Dazu werden die Bootstrap CSS-Klassen verwendet wie has-errors, ohne dass man das explizit berücksichtigen muss.

image

Der erzeugte und verwendete HTML5-Code aus den Web Server Controls ist einfach zu verstehen und zu verändern. Natürlich kommt das moderne Model Binding zum Einsatz. Man darf sich nicht allzu viel erwarten, aber für einfache Datenbank Admin Frontends ist Scaffolding eine sehr effiziente Methode. Webforms sind eben noch lange nicht tot.

AdcX Call 4 Papers

Vom 21.-22. Oktober findet wieder die jährliche Premium Developer Konferenz ADC statt (Advanced Developers Conference). Ort ist Mannheim,  das Motto wird Cross-Plattform sein, deshalb: ADC X.

ADCLOGO

Wir suchen Sprecher, die zu native und HTML5 basierter Entwicklung für alle Plattformen hochkarätige 80 Minuten-Sessions halten wollen. Wir denken im Web-Umfeld an Plattformen wie Intel XDK, Visual Studio Cordova, oder Phonegap. Natürlich auch an JavaScript, TypeScript, Coffescript und Binding Frameworks wie Angular.js. Auf der nativen Seite suchen wir Themen zu Xamarin, Portable Class Librarys, Shared Projects oder Universal App. Egal ob native oder auf HTML5 basierend, muss ein Service Stack entwickelt werden, der sich heute am REST Architektur Pattern orientiert. Hier denken wir an Themen wie Web API, Owin, Oauth bzw. ASP.NET Identity, Azure vs OnPremise, ASP.NET vNext, Roslyn.

Vorschläge einfach per E-Mail an events@ppedv.de

Der Fokus des Events liegt auf dem Microsoft-Entwickler, der seine Optionen prüfen will um Technologieentscheidungen zu treffen.

Das Internet ausdrucken

An einschlägigen IT-Stammtischen kreisen immer wieder Witze mit der Quintessenz: das Internet backupen, das Internet löschen oder das Internet ausdrucken. Mit dem letzteren habe ich mich beschäftigt. Völlig am Zeitgeist vorbei, wird mit einem Thermodrucker und Visual Basic Winforms ein Twitter Stream gedruckt.

Dafür habe ich mich wirklich in Unkosten gestürzt und den Thermopapier-Drucker Modell D10 aus dem Hause Celectronic für 11,90€ bestellt.

Der Drucker kommt mit einer Parallelschnittstelle und einem USB Adapter. Windows 8.1 erkennt diesen und trägt in den Gerätemanager ein USB Device ein.

image

Als nächstes wird manuell ein Drucker hinzugefügt, der ebendiese Schnittstelle nutzt.

image

Der Thermotransferdrucker kann eigentlich nur ASCII Zeichen mit vordefiniertem Zeichensatz. Deshalb wird der generische Text Only Drucker Treiber gewählt.

image

Im nächsten Schritt wird mit Visual Studio 2013 ein Visual Basic Winforms Projekt erstellt. Die Twitter REST API 1.1 erfordert einen OAuth autorisierten Zugriff. Dazu muss man mit einem Twitter Account die Applikation im Web Interface anlegen und erhält Token und Security Credentials. Diese insgesamt vier Parameter werden von der Anwendung bei jedem Abruf benötigt.

Um mit Twitter, der Authentifizierung und der API so wenig Aufwand wie möglich zu haben, wurde die Library Tweetinvi per Nuget zum Projekt hinzugefügt. Ein Test mit einer alternativen Library LINQ2Twitter schlug fehl.

Es wird die Twitter Search API genutzt, um alle 15 Sekunden eine Suche auf einen Hashtag abzusetzen. Um auf jeden Fall die wichtigen Nachrichten im Fehlerfall nicht zu verpassen, werden immer einfach alle Tweets, die Twitter hergibt, geladen. Mit Hilfe einer separaten Liste, in der anhand der Tweet ID doppelte Einträge vermieden werden, werden dann die Einträge eindeutig gehalten. Diese Liste weiß auch, ob der Eintrag bereits gedruckt wurde. Für die Persistenz wird beim Beenden und Starten die Liste serialisiert bzw. deserialisiert , so dass niemals etwas doppelt gedruckt werden sollte..

Wer schon einmal mit XAML gedruckt hat, wird völlig entgeistert feststellen, wie einfach das unter Winforms läuft.

Der Testaufbau mit einem Acer W3 Tablet mit Windows 8.1:

printtwitter

nun noch der VB.NET Beispiel Code

   1:  Imports Newtonsoft.Json
   2:  Imports System.IO
   3:  Imports Microsoft.VisualBasic.PowerPacks.Printing
   4:  Imports System.Drawing.Printing
   5:  Imports Microsoft.VisualBasic.PowerPacks.Printing.Compatibility.VB6
   6:   
   7:  Public Class Form1
   8:      Dim key As String = "oY...............3"
   9:      Dim secret As String = "rqV..................................u"
  10:      Dim atoken As String = "155...........................CB"
  11:      Dim stoken As String = "y9.................................bx"
  12:      Dim tweetlist As New List(Of twittermsg)
  13:   
  14:     
  15:   
  16:      Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
  17:          On Error Resume Next
  18:          tweetlist = JsonConvert.DeserializeObject(
Of List(Of twittermsg))(File.ReadAllText("daten.json"))
  19:      End Sub
  20:      Private Sub Form1_Closing(sender As Object, 
e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
  21:          File.WriteAllText("daten.json", JsonConvert.SerializeObject(tweetlist))
  22:      End Sub
  23:   
  24:      Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
  25:          TwitterCredentials.SetCredentials(atoken, stoken, key, secret)
  26:          Dim tweets = Search.SearchTweets(TextBox1.Text)
  27:          Dim n = tweets.Count
  28:          For Each t In tweets
  29:              If IsNothing(tweetlist.Find(Function(c) c.id = t.IdStr)) Then
  30:                  tweetlist.Add(New twittermsg With 
{.id = t.IdStr, .text = t.Text, .printed = False})
  31:              End If
  32:          Next
  33:          Dim nn = tweetlist.Count
  34:          For Each x In tweetlist
  35:              If x.printed = False Then
  36:                  ListBox1.Items.Add(x.text)
  37:                  Dim Printer As New Printer()
  38:                  Printer.PrintQuality = vbPRPQDraft
  39:                  Printer.Print(x.text)
  40:                  Printer.EndDoc()
  41:                  x.printed = True
  42:              End If
  43:          Next
  44:      End Sub
  45:      Private Sub Button1_Click_1(sender As Object, e As EventArgs) Handles Button1.Click
  46:          Timer1.Enabled = True
  47:          ListBox1.Visible = True
  48:      End Sub
  49:  End Class
  50:  Class twittermsg
  51:      Public Property id As String
  52:      Public Property printed As Boolean
  53:      Public Property text As String
  54:  End Class

DynamicEntity Error Message

Vier … vier Stunden habe ich einen Fehler gesucht. Ein Entity Data Model mit einem Formview Control, das per Dynamic Data erstellt wird.

Fehlermeldung

Es konnte keine MetaTable bestimmt werden. Es konnte keine MetaTable für die Datenquelle '' bestimmt oder aus der Anforderungs-URL abgeleitet werden. Stellen Sie sicher, dass die Tabelle der Datenquelle zugeordnet, die Datenquelle mit einem gültigen Kontexttyp und Tabellennamen konfiguriert oder die Anforderung Teil einer registrierten DynamicDataRoute ist.

in Englisch

Could not determine a MetaTable. A MetaTable could not be determined for the data source 'SqlDataSource1' and one could not be inferred from the request URL. Make sure that the table is mapped to the dats source, or that the data source is configured with a valid context type and table name, or that the request is part of a registered DynamicDataRoute.

Was war's? Beim ItemType war ein Kleinbuchstabe drin. Spielt nirgends eine Rolle. Nur offensichtlich bei der Anwendung des DynamicEntity Controls muss der Itemtype case sensitiv zum Namespace bzw. dem Projektnamen passen.

image

ASP.NET DataPager, ModelBinding und JQuery Mobile

Ich habe vor rund einem Jahr schon mit Paging und Listen experimentiert - damals eher erfolglos, die Useability war mangelhaft. Zwischenzeitlich hat JQuery Mobile die Version 1.4 erreicht. Wieder habe ich mit VB.NET und Webform Controls einen neuen Versuch gestartet und ich bin begeistert. Einfacher geht's nicht.

Die Select-Methode im Codebehind der ASPX-Seite enthält irgendwas, was eine Liste vom Typ IQueryable zurück gibt, Kein Parameter in der getData Methode, kein LINQ. Einfach nur return asQueryable. Dazwischen pure Magie.

Der Datapager kann völlig frei im deklarativen HMTL-Teil platziert werden. Die Steuerung wird über das PagedControlID vorgenommen. Nach Analyse des gerenderten HTML-Code mit den F12 Browser Tools wurden aus Numerischen Hyperlinks durch Zugabe u-btn, eben Buttons. Diese werden gruppiert mit Controlgroup.

   1:  <asp:DataPager ID="DataPager1" PageSize="20" data-role="controlgroup" 
   2:  data-type="horizontal"
   3:          PagedControlID="ListView1" runat="server">
   4:    <Fields>
   5:       <asp:NumericPagerField ButtonType="Link" NumericButtonCssClass="ui-btn" 
   6:  CurrentPageLabelCssClass="ui-btn ui-btn-active" NextPreviousButtonCssClass="ui-btn" />
   7:     </Fields>
   8:  </asp:DataPager>
   9:  <ul data-role="listview" data-inset="true">
  10:      <asp:ListView ID="ListView1" runat="server" ItemType="JQMsample.ort"
  11:        SelectMethod="FormView1_GetData">
  12:       <ItemTemplate>
  13:           <li><span class="ui-li-count"><%#Item.plz%></span> <%#Item.name%></li>
  14:       </ItemTemplate>
  15:    </asp:ListView>
  16:  </ul>

Hab ich schon erwähnt, dass ich Webforms liebe? Fertig ist die Paged List.

image

ASP.NET Jquery Mobile Flipswitch

Beim Studium der JQM 1.4 Docs finde ich immer wieder relevante Änderungen in der API. Scheinbar ist auch das Verhalten des “Toggle Switch” geändert worden. In einem älteren Beispiel habe ich dafür data-role=”Slider” verwendet.

image

Nun tritt das FlipView Widget an seine Stelle. Das ASP.NET-Webforms-DropDownlist-Steuerelement rendert den benötigten HTML-Code in der Kombination Select und Option.

   1:  <div class="ui-field-contain">
   2:    <label>geschlecht</label>
   3:     <asp:DropDownList BorderStyle="NotSet" ID="RadioButtonList1" runat="server"
   4:         DataValueField="male" data-role="flipswitch">
   5:         <asp:ListItem Value="false" Selected="True">Frau</asp:ListItem>
   6:         <asp:ListItem Value="false">Mann</asp:ListItem>
   7:     </asp:DropDownList>
   8:  </div>

 

Im Browser erscheint der Toggle Switch optimal für Touch-Bedienung.

image

image

Wissen aufbauen und Microsoft Surface Pro 3 kassieren

Month List