ASP.NET Webforms Custom Controls

Seit Ewigkeiten habe ich keine Web Forms Controls mehr geschrieben. Mit Angular.JS Direktiven wird HTML erweitert und man erhält funktionell ein HTML Control. Das kann man natürlich auch Server gerendert, mit ASP.NET.

Die Programmieraufgabe lautet ein Validierungs Control selber zu schreiben. Eine übliche Aufgabe ist ein Prompt der die Daten eventuell noch einmal anzeigt und per JA und Nein bestätigt werden kann.

Dafür benötigt man allerdings einen Mix aus Server und Client Code. Um eine einheitliche Programmier Experience zu haben, wird JavaScript um eine String.format Funktion ala .net erweitert. Das ist geklauter Code, oder wie man auch gerne sagt Open Source.

   1:   String.format = function () {
   2:              var theString = arguments[0];
   3:   
   4:              for (var i = 1; i < arguments.length; i++) {
   5:                  // "gm" = RegEx options for Global search (more than one instance)
   6:                  // and for Multiline search
   7:                  var regEx = new RegExp("\\{" + (i - 1) + "\\}", "gm");
   8:                  theString = theString.replace(regEx, arguments[i]);
   9:              }
  10:              return theString;

 

Als nächstes wird eine Klasse von CustomValidator geerbt. Im Kern muss nur die Prerender Methode überschrieben werden, die HTML und JavaScript in den Client rendert.

   1:  Imports System.ComponentModel
   2:   
   3:  <DefaultProperty("PromptMessage")>
   4:  Public NotInheritable Class PromptValidator
   5:      Inherits CustomValidator
   6:      <DefaultValue("")>
   7:      Public Property PromptMessage() As String
   8:   
   9:   
  10:      Protected Overrides Sub OnPreRender(e As EventArgs)
  11:          Dim message = String.Concat("""", Me.PromptMessage, """")
  12:   
  13:          If PromptMessage.Contains("{0}") AndAlso Me.ControlToValidate <> "" Then
  14:              message = String.Concat("String.format(""", Me.PromptMessage, """, args.Value)")
  15:          End If
  16:   
  17:          Me.ClientValidationFunction = String.Concat("
new Function('sender', 'args', 'args.IsValid = confirm("
, message, ")')")
  18:          Me.EnableClientScript = True
  19:          MyBase.OnPreRender(e)
  20:      End Sub

 

Bereits ab diesem Zeitpunkt  befindet sich das neue Control in der Werkzeugleiste von Visual Studio und kann per Drag&Drop auf das Web Formular gezogen werden.

image

Auch wenn der Designer nicht perfekt ist, zeigt er das Steuerlement korrekt an. Im Quellecode kann man das registrierte Präfix erkennen.

   1:  <%@ Register Assembly="WebApplication5" Namespace="WebApplication5" TagPrefix="ppedv" %>
   2:  <html xmlns="http://www.w3.org/1999/xhtml">
   3:  <head runat="server">
   4:  ...    </head>
   5:   
   6:  <body>
   7:  <form id="form1" runat="server">
   8:  <asp:TextBox runat="server" ID="text1"></asp:TextBox>
   9:  <ppedv:PromptValidator runat="server" PromptMessage="Ihr Wert {0}?"
  10:           ErrorMessage="Ganz falsch" ControlToValidate="text1" 
  11:          ValidateEmptyText="true"/>
  12:          

Profis werden Ihre Controls in Assemblys kompilieren und das registrieren zentral in der web.config vornehmen. Alles in allem trotz fehlender Übung schnell und einfach von der Hand gegangen.

Übrigens werden Web Forms Schulungen noch immer gebucht.

Angular Sicherheitsprobleme

In der Regel bin ich so der Typ “it-works” und das wars. Aber ab und zu komme ich auch auf dumme Gedanken. Wie ich dann feststellen musste, war ich nicht der Erste und das Ergebnis ist erschreckend.

JavaScript Template Engines, wie sie auch von Angular.js bereit gestellt wird, verlagern Logik vom Server zum Browser. Naturbedingt wird dann das Rad neu erfunden. Angular verwendet die doppelt geschweiften Klammern {{ }} um Ausdrücke auszuwerten. In der Praxis gedacht um Werte oder Expressions aus einem View Model zu binden. Diese Werte kommen in der Regel aus einer Datenbank. Klingelt es da? SQL Injection hat sich diesen Gedankengang vor langer Zeit zu eigen gemacht.

Also mal in die Testphase.

  • {{1+2}} zeigt im Browser 3
  • {{alert(‘hallo’)}} zeigt im Browser nichts

Der Grund liegt daran, das Angular nicht per eval den Code auswertet, sondern mit einem eigenen Interpreter. Wie genau kann man in der Angular Dokumentation nachlesen. Alles was auf das DOM zugreift und noch viel mehr wird gefiltert. Wer sich lange mit Security beschäftigt, wird wissen, das dies der völlig falsche Ansatz ist. Frühe Ansätze SQL Injection per Regular Expression zu verhindern, gingen den gleichen falschen Weg. Sichere System werden komplett dich gemacht und nur das erlaubt, was definiert für den Task benötigt wird.

Wie es Angular im Detail löst, entzieht sich meiner Kenntnis. Jedenfalls habe ich eine Menge an Tricks im Web gefunden, um aus dieser Sandbox auszubrechen. Alle basieren auf JavaScript als String, das mit ein wenig Tricks zu ausführbaren Code wird.

Matthias Karlsson demonstriert das unter anderem in einem Video. Dieses Exploit wurde vom Angular Team gefixt.

Der Fix löst aber das Problem nicht. Es gibt anders als bei einem Windows Betriebssystem weder ein automatisches Update, noch einen Hersteller der dafür haftet. Eine Microsoft kann es sich nicht erlauben, ein Security Issue ungefixt zu lassen. Open Source Lösungen schieben diese Verantwortung zum Betreiber der Lösung- also der Website. Gerade im Webumfeld lässt sich supereinfach die Version des JavaScript Framework feststellen und liefert damit einen Angriffsvektor.

Darüber hinaus existieren auch aktuelle Sicherheitslecks, um aus der Sandbox auszubrechen. Und es werden immer wieder Neue auftauchen.

Ein relativ neuer Angriff nimmt den $$watcher als Basis. Ganz leicht per JSFiddle für den nächsten Copy Paste Hack. Der Autor  beschreibt den Sandbox Escape detailliert.

Ist das alles schlimm oder eher akademischer Natur. Alles easy solange es keiner ausnutzt. Die nächste XSS Attacke wartet nur.

Darüber hinaus habe ich ein Wiki gefunden, das Einstiegs Hilfe für den böswilligen Angreifer liefert.

Fazit

Erschreckend wie einfach man Angular basierte Websites hacken kann. Dabei liegt das Problem im Kern der JavaScript durch JavaScript ausführenden Web Frameworks. Experten können das mit überschaubaren Aufwand in den Griff bekommen. Das aber nur solange aktiv an den Bedrohungsmodellen gearbeitet wird. Die Agilität der JS Frameworks und die steigend Anzahl von Directive oder Modulen die  schnell und gerne eingefügt werden, lassen einen sicheren Betrieb meiner Meinung nach im Grunde nach nicht zu.

Angular.JS ohne $scope

In Angular ist der Scope die technische Implementierung des Viewmodels. Obwohl einfach zu verstehen und verwenden ist angekündigt mit der Version 2.0 darauf zu verzichten. In der Tat ist ein Fehler in der Scope Hierarchie mitunter schwer zu finden.

Folgender Blog Artikel ist rein akademisch und zeigt zwei Wege auf einen Controller in Angular.js zu schreiben bzw Daten deklarativ in HTML zu binden.

   1:  <form id="form1" runat="server" ng-app="app">
   2:          <div ng-controller="myController">
   3:              <input ng-model="person.name" />
   4:<input ng-click="myclick()" type="button" value="click" />
   5:          </div>
   6:   </form>
   7:   
   8:   <script>
   9:         var app = angular.module('app', []);
  10:          app.controller('myController', ['$scope', function ($scope) {
  11:             $scope.person = { name: 'Hannes' };
  12:             $scope.myclick = function () {
  13:             $scope.person.name = "Franz";
  14:              };
  15:       }]);
  16:   </script>

 

Die Scope freie Alternative: Durch die Nutzung der Controller AS Syntax im HTML Teil entfällt $scope als Instanz des Viewmodels. Im Controller kann kann per this auf Methoden und Eigenschaften zugegriffen werden. Über die Extend Methode wird das JavaScript Objekt erweitert.

   1:  <form id="form1" runat="server" ng-app="app">
   2:    <div ng-controller="myController as alias">
   3:        <input ng-model="alias.person.name" />
   4:        <input ng-click="alias.myclick()" type="button" value="click" />
   5:  </div>
   6:  </form>
   7:   
   8:  <script>
   9:     var app = angular.module('app', []);
  10:     app.controller('myController',myCtrl);
  11:     function myCtrl() { };
  12:     angular.extend(myCtrl.prototype, {
  13:              person : { name: 'Hannes' },
  14:              myclick: function () {
  15:              this.person.name="Frnaz";
  16:          }
  17:     });
  18:  </script>

 

Nach einer weile nachdenken, noch eine einfachere Scope freie Version eines Angular Controllers.

   1:  var app = angular.module('app', []);
   2:          app.controller('myController', [function () {
   3:              var vm = this;
   4:              vm.person = { name: 'Hannes' };
   5:              vm.myclick = function () {
   6:                  vm.person.name = "Franz";
   7:              };
   8:          }]);

 

Den gewöhnlichen Teilnehmer einer Angular Schulung überfordert dies eindeutig. In meinem Angular Training bleibe ich bei der Scope Variante.

If you pay Peanuts- you get Monkeys

Gerne zitierte Phrase im Zusammenhang mit mäßig motivierten Mitarbeitern. Unabhängig davon das ich den direkten Zusammenhang zwischen Geld und Leistung bisher in der Praxis nicht erfahren habe, stellt sich die Frage, wie korreliert Bezahlung und Motivation genau. Natürlich hat jeder Mensch Grundbedürfnisse, die erfüllt sein müssen. Aber alles was darüber hinaus, geht schlägt sich nicht immer in ein mehr an Motivation nieder. Manchmal sogar ins Gegenteil.

Aus der Sicht des Arbeitgebers stehen allerdings Kosten und Leistung sehr wohl in einer starken Abhängigkeit. Je nach Region und Geschäftsmodell muss der Ertrag eines Mitarbeiters seine direkte Kosten (ca  Jahresbrutto *1,35) mindestens um den Faktor 2-3 übersteigen um überhaupt in die Gewinnzone zu kommen.  Darin unterscheidet sich rein kaufmännisch betrachtet eine menschliche nicht von einer sonstigen Ressource. Wenn die Rechnung nicht stimmt, ist über kurz oder lang jeder Arbeitsplatz weg. Industriebranchen wie Textil oder Stahl gehen an dieser simplen Formel zugrunde.  Folglich muss jedem Berufseinsteiger bewusst sein, je höher sein Verhandlungserfolg, desto wahrscheinlicher sein Scheitern.

Trotzdem klafft häufig eine Lücke zwischen selbst Wahrnehmung und dem Jahres Brutto. Genau dann kommt aus der Mitarbeitersicht der Widerstand auf. Man ist häufiger krank und bringt in der übrigen Zeit den Tag auf Facebook hinter sich. Braucht sich der Chef nicht zu wundern. If you pay Peanuts – you get Monkeys.

Vergeblich habe ich versucht die Quelle oder den Urheber des Zitats zu finden, um den ursprünglichen Kontext wieder herzustellen. Nun werfe ich mal als Gendanken eine alternative Interpretation auf.

Warum machen Menschen irgendwas, in einer in allen Bedürfnissen übersättigten Zeit? Jedes Jahr ein neues iPhone kaufen? Aber Menschen gehen nach wie vor zur Arbeit, sind bei der Freiwilligen Feuerwehr oder helfen einem Freund beim Haus bauen.

Schlicht weil sie es wollen, also intrinsisch motiviert. Wenn man nun jemanden für etwas was er regelmäßig und gerne macht, kleine Belohnungen in Aussicht stellt, wird das Ergebnis ganz kurz besser und dann bestenfalls gleicht gut funktionieren. Wenn die Sonderleistung (die Erdnuss) gestrichen wird, wird sich die Einstellung durchsetzen, in einer Art Trotzreaktion, die Leistung zu verweigern. Unzählige Studien beschäftigen sich mit der Thematik intrinsische und extrinsische Motivation und deren Auswirklungen. Die Ergebnisse deuten alle in die selbe Richtung. Nur wenn der finanzielle Sonderreiz sehr hoch ist, also deutlich mehr als eine Erdnuss, wird sich jemand auch gesondert bemühen.

Wenn man also einem Menschen für bewertbare Leistungen (zb. Rasenmähen), kleine Bonis gewährt (5€) wird der Mensch zum dressierten Affen, der ohne diese Zuwendung passiv wie ein Affe verharren wird.

Moderne Management Systeme versuchen über Ziele und  Kennzahlen die Mitarbeiter zu managen und versprechen dabei bei Erfüllung entweder sehr viel oder aus Sicht des Mitarbeiters lediglich Peanuts. Das ist eine moderne Art von Zirkusdressur. Dagegen wehren sich moderne gebildete Menschen.

Was denkst Du? Follow up an hannesp@ppedv.de

Bedeutung von Open Source in 2015

Bei einem Bier Gespräch mit Norbert Eder, kam das Thema auf meine aktuelle Meinung zu Open Source. In der Community ist ein Blog Eintrag vor ca zweieinhalb Jahren durchaus heftig diskutiert worden. Fazit daraus, die Verfügbarkeit von Quellcode unter OS Lizenz hat keine Bedeutung für mein Business. In  der Zwischenzeit ist viel passiert, einiges was meine damalige Meinung stützt und anderes was meine Sicht auf die Dinge verändert hat.

Open Source basierte Software ist nicht besser oder sicherer als Closed Source. Dieses Thema hatte ich anlässlich des Sicherheits Problems Heartbleed aufgegriffen. Es fehlt schlicht jeder Beweis für die häufig vertretene These, das hunderte Entwickler den Code prüfen und damit Sicherheitsprobleme sofort auffallen und gelöst werden.

Aus der Sicht als Microsoft Kunde, hat die Veröffentlichung des Quellcodes in der Vergangenheit praktisch meist das Ende des Produktes bedeutet. In jedem Fall wurden Developer Ressourcen abgezogen und die Qualität leidet.

Mein Bedürfnis Quellcode einer Bibliothek zu lesen und vielleicht sogar einen Bug zu fixen hält sich erheblich in Grenzen. Gleiches gilt für Consumer und sicher auf in weiten Teilen für den Enterprise Kunden. Norbert führte ins Feld, das er die Möglichkeit nutzt und auch schon mal Code zurück geleifert hat, neudeutsch contributed. Für mich habe ich dies in den Anfängen von .NET mit ildasm ab und angenutzt um IL Code zurück zu Compilieren und auch mal eine Klasse mit diesem Fragmenten neu zu schreiben. Mit steigender Funktion und Stabilität von .net hat sich dies erübrigt.

Nur ein sehr kleiner Teil der Community ist fähig und willig Code zu contributen. Aus einer konkreten Problemstellung in Angular, kann man auf github nachvollziehen, das es mit der Innovation und den kurzen Zyklen nicht immer so weit her ist. Konkret fehlt eine häufig gewünschte Funktion seit fast drei Jahren.  Angular ist ohnehin ein Spezialfall, weil Google getrieben und bezahlt. Trotzdem wird nur  Support von ca 18 Monaten angekündigt. Im Vergleich dazu bei Microsoft Silverlight zehn Jahre. Wie die Erfahrung zeigt, kann das Ende in jedem Fall schnell und überraschen kommen- in dieser Hinsicht steht es 1:1.

Dabei gibt es durchaus eine Reihe von Leuten die außerhalb des Angular Projektes den Aufwand getrieben haben und dieses fehlende Feature entwickelt haben. Dazu gehöre auch ich. Allerdings findet sich meine Lösung als Blog Beitrag, schlicht weil ich den Aufwand mit Github nicht treiben möchte und auch Zweifel habe ob meine Lösung wirklich optimal ist. Was ich definitiv nicht brauche ist emotionale Diskussion bis hin zum Shitstorm meiner Arbeit, Norbert Eder fordert in diesem Kontext mehr Mut und verspricht sich davon die persönliche weiter Entwicklung.

Welche Auswüchse die Selbstorganisation von Open Source Projekten annehmen kann, sieht man an Node.js oder Angular 2. Erst passiert längere Zeit nichts, dann gibt es eine Abspaltung, Fork genannt und keiner weis so recht, wie es weiter geht. Durchaus häufig Bloggen Core Entwickler Ihren Unmut und die Beweggründe für Ihren Ausstieg, was dem Projekt nicht zuträglich ist. Natürlich kann das bei Unternehmen auch passieren, allerdings sind diese für Ihre Produkte haftbar. Das kann richtig ins Geld gehen. Open Source Projekte sind da fein raus, da haftet niemand. Mitarbeiter sind überdies Vertraglich zur Verschwiegenheit verpflichtet.

OS Bibliotheken werden in der Regel völlig Enthusiastisch von der Community aufgenommen  und über Nacht zum defacto Standard deklariert. Wer Zweifel äußert, hat nicht verstanden oder sich noch nicht hoch genug in die spirituellen Welten begeben.

Wenn Monate später Design oder Performance Ziele nicht erreicht wurden, wird still und heimlich eine neue JavaScript Sau durchs Dorf getrieben. Da bleibt keine Zeit für Manöver Kritik und Analyse des Scheiterns. Hintergründe sind bestenfalls einer Handvoll Insidern bekannt.

In einem User Group Vortrag von Mike Bild zum Thema Microservices, fiel nebenbei die Bemerkung “mit dem alten Zeugs, bekommst schlicht keine Entwickler mehr”.  Das geht sogar soweit, das jeder Service mit einer eigenen Technologie gebaut werden kann. Ein Gedanke der sich mit der generellen Veränderung des Weltbildes der heutigen Berufseinsteiger gut deckt. Mann will selbstbestimmt leben. Ein Pflichtenheft degradiert dabei zum Code Monkey. Das bedeutet das es Technologie Entscheidungen gibt, die die Anzahl der Bewerber erheblich steigern können. Richtig- die ganze Java Script Welt scheint  aus diesen Nektar zu sprießen. Die agilen Methoden liefern genau dafür Management freie Umgebungen. Jeder tut was er kann und will. Der Kontrollverlust ist Horrorvorstellung für fast jeden Entscheider.

Microsoft setzt seit einigen Jahren auf Open Source, weit über das Ajax Control Toolkit hinaus. Man fragt sich warum. Wo wird dadurch Geld verdient? Speziell da sich der Redmonder Hersteller diesen Projekten regelrecht anbiedert und dabei die gestandenen Microsoft Kunden gefühlt im Regen stehen lässt. Seit Windows 8, also schon vier Jahre, werden JavaScript und co propagiert. Der einzige Zweck kann nur sein, Teile der nicht Microsoft Welt abzuholen. Gefühlt ohne große Resultate, dafür aber plötzlich mit einem Migrationspfad, der weg von Microsoft führt. In der Tat sind einige MVP’s in der Zwischenzeit stolze Mac User mit veränderten Entwicklungsfocus.

Gern zitiertes Argument pro Shared und damit Quell Offener Software ist der letztendlich verlorene Kampf der Microsoft Encarta vs Wikipedia. In erster waren viele Entwickler und Autoren beschäftigt und bezahlt. Wikipedia arbeitet kostenfrei und sogar (fast) ohne Werbung.

image

Auch Wikipedia kennt die Community üblichen Grabenkämpfe zwischen der für Reinheit kämpfenden Elite und anderen Autoren. Auch Wikipedia braucht Geld. Das allerschlimmste aber, es ist nur Platz für ein einziges Wikipedia. Es kann keine Konkurrenz und damit auch keine Innovation mehr gegeben. Die Zukunft wird eine Welt der Monopole bringen.

Die Microsoft Openess gipfelt in der Veröffentlichung von Kern Teilen des .NET Frameworks, Ich könnte meinen ASP.NET 5 Code nun teilweise auf einem iOS hosten. Warum sollte ich das? Ich würde mir mehr wünschen, das Silverlight auf iOS oder Android läuft. Aber das ist eine andere Geschichte.

Die neue selbstbestimmte Generation findet also sich und den Shared Gedanken in Open Source wieder. Diese Mitarbeiter sind damit intrinsisch motiviert und schaffen auf Vertrauensbasis. Soweit das Ideal. Allerdings wechselt Motivation und unterliegt der Tagesverfassung. Man hat Sorgen, Krankheit  oder einen blöden Chef der das alles nicht versteht. Produkte müssen trotzdem fertig werden. Den durchaus nicht neuen agilen Gedanken findet man als Vorgehensmodell in SCRUM definiert. Den größten Vorwurf den ich z.B. Scrum mache ist, das von einer idealen Welt ausgegangen wird. Der krank feiernde Kollege existiert darin nicht.

Auch Open Source enthält Übles und wir haben keine Mechanismen damit umzugehen. Paket Manager werfen gnadenlos zehntausende Zeilen Code in das Projekt. Selbst wenn man alles validieren würde, erlauben es die extrem kurzen Zyklen nicht, den Code Fehlerfrei zu halten. Enterprise Kunden stiegen dann aus npm und nuget aus und pflegen ihren veralteten Open Source Code selber weiter. Persönlich erwarte ich den ein oder anderen Sicherheitsgau auf uns zukommen.

Allerdings hat Open Source wesentliche Impulse geliefert um in diesem Umfeld überhaupt Software produzieren zu können. Das öffnen einer Issue List für jedermann, die kurzen Zyklen und das ggf. direkte Eingreifen in den Code findet man in Wasserfall basierenden Modellen nirgends. Diese dafür entwickelten Konzepte erlauben es nun viel schneller Produkte in den Markt zu bringen. Der vorläufige Höhepunkt aus der Open Source Community ist DevOps mit Vermischung von Administration und Programmierung. Die Release Zyklen gehen dabei bis in den Minutenbereich und erlauben dann kaum noch automatisierte Tests.  Codieren sozusagen am offenen Herzen. Nichts desto trotz sind die Vorgehensweisen essentiell beim Fixen on Hot Bugs in stark genutzten Web Anwendungen. Einen mehrstündige Down kann sich eine Azure Cloud nicht leisten.

Open Source wird weiter das Business aufrollen. Getrieben vom Trend der Shareconomy. Persönlich sehe ich das nur als schmalen Aspekt einer tiefgreifenden gesellschaftlichen und wirtschaftlichen Veränderung. Welche Risiken und Veränderungen sich daraus ergeben, lässt sich nicht einmal im Ansatz abschätzen. Bei weiten Teilen der Community spielt Risiko Betrachtung aktuell gar keine Rolle mehr. Letztendlich bleibt auch die Frage offen wie unsere Geschäftsmodelle der Zukunft aussehen werden, wenn plötzliche keine Software Lizenzen  mehr verkauft werden.

Boostrap Toogle Switch mit Angular Direktive

Was Jquery Mobile mit dem Flipswitch kennt, sucht man bei Bootstrap vergeblich.

image

Da es ziemlich naheliegend ist, fordert die Community auf Github von Bootstrap seit drei Jahren das Feature. Irgendwie vergeblich. Da Open Source, kann man das natürlich selber schreiben und ins Projekt einchecken. Viele tun das scheinbar nicht. Man findet jede Menge Lösungen offsite, die allerdings in Funktion und Qualität nicht ganz den Ansprüchen genügen. Also selber machen.

Das Layout könnte im HTML Code z.B. so gelöst werden

   1:  <div class="btn-group">
   2:       <a class="btn btn-xs btn-primary active">Wert</a>
   3:       <a class="btn btn-xs btn-default">Wert2</a>
   4:  </div>

Ist optisch nicht ganz ein Flipswitch, aber leicht anpassbar.

image

Für den Zustandswechsel wird ein Stück JavaScript benötigt, das die Klassen btn-primary und btn-default austauscht.

Hier wird aber weiter gedacht. Der Wert soll an ein Viewmodel eines Angular.js Controllers gebunden werden.

   1:    .controller('myController', ['$scope', function ($scope) {
   2:                 $scope.wert = true;

 

Der HTML Teil wird mit einer Angular Direktive erstellt. Als Parameter werden die beiden Beschriftungen übergeben.

   1:  <div class="btn-group" 
   2:     my-toggle my-text1="meins" my-text2="public" model="wert">
   3:  </div>

 

In meinem Angular Trainings lernt man die genauen Details zu Direktiven. Auf einige Angular Stolpersteine soll hier aber hingewiesen werden.

Mit dem Template wird HTML Code in der Page erzeugt, der die beiden Buttons enthält. Komplizierter ist die Gültigkeit des Scope, der das Viewmodel aus dem Controller hält und letztendlich den checked Wert enthält. Wie kann man aus einer Direktive auf den Scope des Controllers zugreifen und diesen auch verändern? Da es mehrere geschachtelte Scopes gibt, somit auf den Parent Scope.

Mit Chrome und der Batarang Erweiterung kann die Internas der Scope Hierarchie auch darstellen.

image

image

Im HTML Code wurde vorher das Attribut model eingeführt, das auf die Property wert (also $scope.wert) bindet. Leider verhält sich die Bindung auf den my-text obwohl optisch ident völlig anders.

In der Direktive wird gesteuert, welche Attribute (@) und Bindungen (=) in den privaten Scope übernommen werden. Nun kann in der Click Funktion des DIV! der Parent Scope ($scope.wert) per Child Scope (scope.model) geändert werden, weil das = eine zwei Wege Bindung bewirkt.

   1:  .directive('myToggle', function () {
   2:         return {
   3:                    restrict: 'A',
   4:                      scope: {
   5:                             model: '=',
   6:                             myText1: "@",
   7:                             myText2: "@"
   8:                         },
   9:                         template: '<a class="btn btn-xs active" 
ng-class="model ? \'btn-primary\' : \'btn-default\'">{{myText1}}</a>'
+
  10:                        ' <a class="btn btn-xs " 
ng-class="model ? \'btn-default\' : \'btn-primary\'">{{myText2}}</a>'
,
  11:                         link: function (scope, element, attr) {
  12:                             element.bind('click', function () {
  13:                                 scope.model = !scope.model;
  14:                                 scope.$apply();
  15:                             });
  16:                 }
  17:           }
  18:     })

Bootstrap mehrfach Navbar

Einige Zeit habe ich über der Usability einer Web Anwendung gegrübelt. Aktuell verwenden wir das Projekt um Realtime Feedback, vor während und nach Konferenz Sessions, zu bekommen. Die Idee ist einen lernen-wissen-teilen Zyklus weit über die eigentliche Konferenz hinaus zu etablieren.

Nächste Woche auf der GUI&DESIGN in Berlin, wird das Projekt wieder eingesetzt. Da wir unter anderem mobile Devices mit dieser Web App adressieren, folgt das UX dem responsive Design Paradigma. Framework ist Bootstrap.

Jede Konferenz Session kann einzeln von Teilnehmer  mit bis 5 Sternen bewertet oder mit Text Kommentaren versehen werden. Das Problem ist der begrenzte Bildschirm. Wie präsentiert man bis zu 30 Sessions gleichzeitig auf einem Smartphone? Nach einem Pair UX Review mit Martin Hoppe von Maximago, kam der Gedanke auf, das von der Bedienung wie eine Bootstrap Navar zu lösen.

Damit waren folgenden Anforderungen definiert

  • Mehrstufige Navbar
  • Navbar Toogle Button dauerhaft anzeigen
  • Menüpunkte nur bei Drop Down
  • Menü schließen bei Auswahl
  • mehrspaltiger Navbar Collapse Bereich

Da fertige UI auf einem iPhone Emulator

image

Und der nicht ganz perfekte multi drop down Navbar Anwendungsfall

image

Die Steuerung des AufZu einer Navbar, wird über ein UI Element mit dem Attribut data-toggle ausgelöst. Das Ziel ist eine Klasse oder ID eines DIV Elements, hier als collapse2 bezeichnet um einen Unterschied zu navbar-collapse des Top Menüs zu haben. Der Z Index  ermöglicht der Top Navbar sich über die zweite Reihe Navbar zu entfalten. Der Abstand top entspricht der Höhe der Top Navbar.

   1: <nav class="navbar navbar-inverse navbar-fixed-top always-open" 
style="top: 50px;z-index:999;">
   2:    <div class="navbar-header">
   3:      <a class="navbar-brand" href="#">Room {{target}}</a>
   4:        <button type="button" class="navbar-toggle"
   5:           data-toggle="collapse" data-target=".navbar-collapse2">
   6:           <span class="icon-bar"></span>
   7:           <span class="icon-bar"></span>
   8:           <span class="icon-bar"></span>
   9:       </button>
  10:     </div>
  11:              
  12:  <div class=" navbar-collapse2 collapse" >

Die ASPX Seite setzt sich aus einer Masterpage und einer Content Page zusammen. In der Content Page (gern auch View) wird das CSS  von Bootstrap in einem Style Block überschrieben und ergänzt. Ziel ist es das Verhalten der Second Navbar zu ändern (always-open). Diese ist dann nicht mehr Responsive, sondern verhält sich so wie eine Navbar im Smart Device Modus.

   1:  .navbar {
   2:     margin-bottom: 0 !important;
   3:          }
   4:  .navbar.always-open {
   5:     border-radius: 0;
   6:           }
   7:  .navbar.always-open .navbar-header {
   8:     float: none;
   9:           }
  10:  .navbar.always-open .navbar-toggle {
  11:     display: block;
  12:           }
  13:  .navbar.always-open .navbar-collapse {
  14:     border-top: 1px solid transparent;
  15:     box-shadow: inset 0 1px 0 rgba(255,255,255,0.1);
  16:            }
  17:  .navbar.always-open .navbar-collapse.collapse {
  18:     display: none !important;
  19:            }
  20:  .navbar.always-open .navbar-nav {
  21:     float: none !important;
  22:     margin: 7.5px -15px;
  23:             }
  24:  .navbar.always-open .navbar-nav > li {
  25:             float: none;
  26:             }
  27:  .navbar.always-open .navbar-nav > li > a {
  28:     padding-top: 10px;
  29:     padding-bottom: 10px;
  30:             }
  31:  .navbar-collapse2 {
  32:     padding-right: 15px;
  33:     padding-left: 15px;
  34:     overflow-x: visible;
  35:     -webkit-overflow-scrolling: touch;
  36:     border-top: 1px solid transparent;
  37:     -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1);
  38:     box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1);
  39:           }
  40:   
  41:  body {
  42:     padding-top: 100px !important;
  43:          }

 

Die beiden Attribute Data-Toggle und data-target werden dann in den einzelnen Listen Einträgen verwendet, um die Navbar nach Selektion auch wieder einzuklappen. Die Navbar Collapse Liste setzt sich dabei in der Regel aus UL und LI Elementen zusammen. Die LI Element werden einfach in der Breite geschrumpft. Für drei  spaltig auf einen Wert <33% und auf block formatiert.

   1:  <li  title="<%#Item.roomname%>" style=" width:32.6%; display: inline-block">
   2:  <a href='/chat#<%#HttpUtility.UrlEncode(Item.shortname)%>'
   3:  data-toggle="collapse" data-target=".navbar-collapse2"

 

und so sieht der normale Browser Benutzer die Web App

image

Viel Freude damit.

easy Datenbindung MVVM und XAML

Ich erinnere mich noch recht gut an meine ersten Silverlight Schulungen. Das Thema zwei Wege Datenbindung und die Benachrichtigungsevents ans Userinterface, war für den Kursteilnehmer immer etwas mühsam. Nun komme ich aus einem Vortrag auf der #ADCX und hab ganz Beiläufig fody kennen gelernt. Und die Welt ist schöner geworden.

Zur Erinnerung: Um einem Model die Fähigkeit zu geben, eine Änderung der Daten dem User Interface mitzuteilen, muss das Interface INotfiyPropertyChanged implementiert werden. Pro Eigenschaft muss dann das ProperChanged Event, mit dem Namen des Propertys als String Argument, ausgelöst werden. Mal abgesehen von der Tipperei, eine perfekte Fehlerquelle. Mit .net 4.0 wurde dann das CallermemberAttribut eingeführt, das dem Compiler erlaubt, den Wert zuzuweisen. In Silverlight 5 muss man einen Trick verwenden, um das Attribut überhaupt nutzen zu können.

   1:  <AttributeUsageAttribute(AttributeTargets.Parameter, Inherited:=False)>
   2:  Public NotInheritable Class CallerMemberNameAttribute
   3:      Inherits Attribute
   4:  End Class

Ohne obigen Code wird folgender VB.NET Code in einem Silverlight Projekt nicht kompilieren

   1:  Public Class person
   2:      Implements INotifyPropertyChanged
   3:      Property id As Integer
   4:      Private _name As String
   5:      Public Property name() As String
   6:          Get
   7:              Return _name
   8:          End Get
   9:          Set(ByVal value As String)
  10:              _name = value
  11:              OnPropertyChanged()
  12:          End Set
  13:      End Property
  14:   
  15:      Protected Sub OnPropertyChanged(<CallerMemberName> 
Optional propertyName As String = Nothing)
  16:          RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
  17:      End Sub
  18:      Public Event PropertyChanged(sender As Object, 
e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged
  19:  End Class

 

Die Zwei Wege Bindung wird nur für das Property name implementiert. Es muss die Langform mit Getter und Setter verwendet werden um in letzteren das Änderungs Event auszulösen (Zeite 11). Der Compiler ersetzt in Zeile 11 den Wert des Parameters propertyName mit “name”.

Es gib wohl Menschen die sich den Gedanken der Compiler Services noch tiefer zu Gemüte geführt haben. Auf Basis von Fody existiert ein Plugin für NotifyPropertyChanged, das man sich per Nuget in seine Visual Studio Projekt installieren kann.

image

Ab jetzt ist es nur noch geli einfach. Aus je zehn Zeilen Code wird eine. Es reicht eine Klassenattribut einzufügen und die verkürzte Propertysyntax.

   1:  <ImplementPropertyChanged>
   2:  Public Class person
   3:      Property id As Integer
   4:      Property name As String
   5:  End Class
Der Compiler erzeugt daraus im wesentlichen die Langversion des Codes, wie im vorigen Beispiel demonstriert.

PS fast auf den Tag genau vier Jahre sind vergangen seit Bob Muglia beiläufig Silverlight für Tod erklärte. Nur drei Monate später musste Bob der damalige Chef von Server und Tools seinen Stuhl räumen. HTML5 reicht auch heute noch bei weitem nicht an Silverlight heran.

Expression Blend UX Guides

Es ist wahnsinnig einfach schlechtes Design zu entwerfen. Aber es ist auch relativ einfach gute User Interfaces zu bauen, wenn man die Grundregeln kennt. Um ein klares Layout (Clean Layout) zu erstellen braucht das UI ein Schema. Mit einem typografischen Grid Layout kann man die UI Elemente wie Text und Bilder strukturieren und ausrichten.

(Quelle Wikipedia)

Visual Studio 2013 erlaubt es ein Raster einzublenden und neu erzeugte Controls an den unzähligen Führungslinien auszurichten.

image

Expression Blend für Visual Studio 2013 kann da schon einiges mehr. Wenn man im Designer vom Lineal per Maus Drag und Drop auf das UI zieht entstehen blaue Führungslinien. Diese werden Rulers und Guides genannt.

image

Dieses UI Schema kann man sogar speichern um es später in anderen XAML Seiten wieder zu verwenden. Im Menü View – Manage Guides auswählen.

 image

Besonders praktisch, Blend bietet auch eine Reihe von vordefinieren Guidelines  zur Auswahl. Für eine Windows Store App (vormals METRO) sind das

  • BasicPage
  • FileOpenPicker
  • GroupDetailPage
  • GroupedItemsPage
  • HubPage
  • ItemsPage
  • SearchResultsPage
  • SettingsFlyout
  • ShareTargetPage
  • SplitPage

Die GroupItemsPage Vorlage

image

Expression Blend für Visual Studio 2013 ist der Nachfolger von Blend 4.0. Damit lassen sich WPF, Silverlight und WIndows 8.1 Apps (HTML und XAML) Designen. Expression Studio 4 wurde komplett eingestellt. Der Nachfolger ist direkt in Visual Studio integriert und benötigt keine separate Lizenz. Mehr zu UX Design gibt es auf der GUI&DESIGN Konferenz in Berlin. Der Autor gibt auch 2-tägige Blend Schulungen.

Layoutrounding mit Expression Blend

Pixel sind niemals rund. Wenn man es genau nimmt sind die realen Pixel quadratisch. Es gibt eine Reihe von Fällen indem die Umrechnung der virtuellen Pixel in die physikalisch vorhandenen erhebliche Probleme aufwirft. Man kann keinen halben Pixel füllen. Windows versucht alles erdenkliche solche Effekte zu minimieren. Dazu kommt das mit dem High DPI Displays zumindest dieses Problem, für das ungeübte Auge nicht zu erkennen ist. Die Funktion nennt sich Layoutounding. Damit wird ein mathematisch halb zu füllendes Pixel ganz gefüllt.

In XAML bestimmt das Container Element wie die Inhalte gerendert werden. Silverlight macht dies automatisch, in WPF ist diese Funktion deaktiviert. Folgendes WPF Beispiel zeigt di Problematik in Expression Blend für Visual Studio 2013.

   1:  <Canvas x:Name="LayoutRoot" Background="White"  UseLayoutRounding="True">
   2:  <Ellipse Fill="#FFF4F4F5" HorizontalAlignment="Left" Height="10" 
   3:  Stroke="Black" VerticalAlignment="Top" Width="10" 
StrokeThickness="0.2" Canvas.Left="245" Canvas.Top="174"/>
   4:  <Ellipse Fill="#FF1717F1" HorizontalAlignment="Left" Height="8" 
   5:  StrokeThickness="0.2" VerticalAlignment="Top" Width="8" 
Canvas.Left="246" Canvas.Top="175"/>
   6:  </Canvas>

Es gibt einen Aussenkreis mit nur 1 Pixel Abstand, der mit einer 0,2px Linie umrandet ist. Nimmt man Silverlight als Projektype sieht das Ergebnis im Visuellen Designer wie erwartet aus. Hier im Bild auf 6000% gezoomt.

layoutrounding2

Alles wie es sein soll. Wenn man den gleichen XAML Code in ein WPF Projekt kopiert und das Attribut UseLayoutRounding  nicht oder auf false gesetzt hat sieht das Ergebnis wie folgt aus

layoutrounding1

Dies mag auf den ersten Blick ein sehr konstruiertes Beispiel sein, soll aber verdeutlichen, das auch bei WPF Pixelgenaues Layout besonderer Aufmerksamkeit bedarf.

Themen wie diese, können Sie auf der GUI&DESIGN Konferenz mit den Experten diskutieren.

Training, Schulung, Sharepoint

Month List