WPF Font einbinden

Google hat mit seiner Design Sprache Material Design unter anderem die Schrift Roboto zum Standard auf Android Devices erklärt. Von dieser gibt e diverse TTF Varianten wie Medium, Light oder Thin. Download der Roboto True Type Font findet sich recht einfach per Suchmaschine.

Um solch eine Schrift in einem WPF Projekt zu verwenden ist quasi nichts notwendig. Am Beispiel von Blend für VIsual Studio 2015 wird ein Verzeichnis Fonts im WPF Projekt angelegt und einfach die Font per Copy Paste reinkopiert.

image

Als nächstes wird ein UI Steuerelement z.B. Textblock dem Window hinzugefügt. In den Eigenschaften steht die Schriftart schon zur Auswahl bereit.

image

Einfacher gehts nicht. Im XAML Code wird wie folgt die neue Font referenziert.

   1:  FontFamily="/BlendkursMUC;component/fonts/#Roboto Medium"/>

Noch besser wird es, wenn man die Font als Resource festlegt.

Zunächst wird auf das schwarze Quadrat (screenshot vorher) der Font Eigenschaft geclickt. Im so erscheinenden Kontextmenü wird der Punkt in neue Resource konvertieren ausgewählt.

Durch folgende Option wird so der XAML Code von vorher als Resource in der App.XAML für das gesamte Projekt definiert.

image

Die Zuweisung erfolgt dann über den gewählten Key

   1:    FontFamily="{DynamicResource FontRoboto}"/>

 

Blend wäre nicht das Designer Tool, wenn es nicht noch einfacher gehen würde. Im Reiter/Fenster Ressourcen werden alle so erzeugten Styles angezeigt. Per Drag und Drop lässt sich so die Font Resource auf jedes UI Element mit einer passenden Font Eigenschaft ziehen.

image

Werte schätzen–Werte schöpfen

Achtung das ist ein non technischer Blog rund um die IT Szene, bunt zusammengewürfelt aus persönlichen Eindrücken.

Meine Facebook Fellows Damir Tomicic und Markus Egger beklagen in selbigen social Network die fehlende Qualität ihres Dell bzw Lenovo Notebooks. Ich muss mich mit meinen Fujitsu quasi nahtlos einreihen, weil nach unbekannten Update der Touchscreen nach Hibernate nicht mehr funktioniert.

Gleichzeitig finde ich und eine Reihe anderer Mitstreiter das Visual Studio bei weitem nicht mehr die Stabilität aufweist, die gewohnt ist. Von Xamarin werden ja wahre Horrorgeschichten in Punkto Qualität verkündet. Der generelle Trend scheint offensichtlich zu sein, seine Software bzw. den Code zu verschenken. Open Source hat in weiten Teilen der Developer Community schon eine fast religiöse Basis. Dabei schützt Open Source vor gar nichts und liefert auch keine nachgewiesene bessere Qualität. Die Dokumentation ist der Code und es darf nichts kosten.

Das boot ver1.jpg

Nun sind wir in der absurden Situation, das der Fotograf der mit seiner Spiegelreflex oder gar mit dem Smartphone auf irgendwas draufhält, nach einer Sekunde “Arbeit” ewige werthaltige Rechte an seinem Werk besitzt. Der Softwareentwickler dagegen publisht seine monatelange Arbeit auf Github und kann bei entsprechender Nützlichkeit, die genannte Sekunde darauf warten, das Nutznießer einen Fork zieht. Ohne das Programmierer jemals ein Recht an der Sache hat oder gar einen wirtschaftlichen Nutzen. Und das besonders erstaunliche ist, die Entwickler finden das auch noch gut. Der Kameramann Jost Vacano von “das Boot” fordert über 30 Jahre nach Drehschluss einen sechsstelligen Nachschlag und wird allem Anschein nach auch damit durchkommen.

Im Jobinterview erklären alle Kandidaten an erster Stelle, die Wertschätzung ihrer Arbeit, als wichtigstes Motivationskriterium. Gleichzeitig wollen sie diese Werke für lau verteilen?

Immer dann wenn das Produkt nichts kostet, bist Du das Produkt.

Ich habe gelernt, das was nichts kostet auch nichts Wert ist. Erst wenn das Bewusstsein erwacht, das bei Verlust dieser Sache unmittelbare Kosten und Aufwand auf mich zukommen, werde ich die Sache entsprechend wertschätzend behandeln. Jeder der Kinder hat, kann dies am Live Experiment beobachten. Entsprechend hat unsere Gesellschaft Geld erfunden und sich, mit all seinen Nebenwirkungen, besser entwickelt, als alternative Modelle. Wir werden älter, das Leben ist leichter geworden.

Software Entwickler müssen Ihren Blick auf die Werte richten, die sie schaffen. Und zwar die mittelbaren und nicht fiktiven zukünftigen. Es muss Menschen geben, denen das Programm, der Dienst etwas Wert ist. Richtig in Geld bemessen. Der Entwickler muss sich jeden Tag überlegen, wie er Mehrwert schafft. Durch Qualität, Dokumentation und Service.

Ganz ehrlich, wer tut das heute wirklich noch?

Doch ich kenne noch solche Unternehmen. Meist vertikale Branchenlösungen, die sehr nah am Kunden arbeiten. Da bleibt keine andere Wahl. Jeder Mittelständler würde sich einen Ast lachen, wenn der Dienstleister die Software 0.1 alpha preview shipped, mit dem Hinweis Bugs doch bitte selber in beiliegen Code zu fixen.

Aber genau das tut die Branche, getrieben von einer zu pesudo Künstlern mutierten Developer Community. Dabei ist es in weiten Teilen was wir treiben -Handwerk.

Ich will wieder mehr Qualität. Von den Softwareherstellern und den Hardwarelieferanten. Dazu muss aber auch Tempo rausgenommen werden. Die von Scrum initiierten 2 Wochen Zyklen können das nicht liefern. Es wird Zeit das das Pendel wieder zurück schwingt. Dann will ich auch gerne dafür bezahlen.

ASP.NET doppeltes Title Element

Nachdem ich heute die Bing Webmaster Tools mal mit der https://ppedv.de website Probiert habe, wird mir in allen ASPX Seiten ein doppelter Page Title Fehler angezeigt.

In der Tat wird nach dem CSS das per Theme eingebunden wird, ein leerers Title Element in den HMTL Code eingefügt.

image_thumb

Da wir vor Jahren schon mal einen diesbezüglichen Fehler in der Seite hatten, konnte ich ausschließen, das es sich um einen Coding Fehler handelte. Weiters ist beim einbinden per link der CSS Datei die Kontrolle schon lange im ASP.NET Stack. Es muss sich über ein Update ein Veränderung des Verhaltens ergeben haben. Die entsprechende Suche ergab, auch andere haben das Problem des doppelten Page Titels mit ASP.NET Webforms.

Die Lösung:

Masterpage enthält vor dem ContentPlaceholder einen leeren Page Title ala

   1:  <head runat="server">
   2:      <meta name="viewport" content="width=device-width, initial-scale=1.0">
   3:      <title runat="server" visible="false"></title>
   4:      <asp:ContentPlaceHolder ID="PlaceHolderHead" runat="server">
   5:      </asp:ContentPlaceHolder>

Wenn kein Title Element gesetzt ist, wird von ASP.NET am Ende des Head Elements autoamtisch  ein leerer TITLE eingefügt.

WPF virtuelles Touch Keyboard

Wer eine WPF Anwendung auf einem Tablet Computer betreiben will, stößt schnell auf Probleme mit der virtuellen Tastatur. Um das OnScreen Keyboard zu aktivieren kann tabtip.exe ausgeführt werden.

Windows 10 bringt aber nun einen Tablet Modus, der weitestgehend das Keyboard automatisch einblendet, wenn der Benutzer den Finger in eine Input Box setzt. Im Desktop Modus von Windows 10 lässt sich dieses per Task Leiste Symbol einblenden.

image

Per XAML Attribut InputScope kann die WPF Anwendung steuern, welches Keyboard Layout verwendet wird. Number zeigt den Ziffernblock, EmailSmtpAddress das @ Zeichen.

image

Eine WPF Anwendung im Tablet Modus wird automatisch im Vollbild Modus ausgeführt. Manchmal erscheint keine Tastatur, dann hilft der Wechsel in eine UWP App, zb Cortana, um das Keyboard zu aktivieren. Allerdings überdeckt die Tastatur die Desktop Anwendung in der unteren Hälfte und damit auch dortige Eingabe Felder.

Angular 1.5 Components vs Direktiven

Zum Zeitpunkt des Blog Artikels befindet sich Angular.js 1.5 in der RC0 Phase. Trotz des kommenden (und völlig anderen) Angular 2 wird weiter am 1er Zweig gearbeitet. In jeder meiner bisherigen Angular Schulungen, waren Direktiven eine echte Hürde für die Teilnehmer. So kommt nun ein etwas einfachere Variante mit den Components in der Version 1.5. Überdies ähnelt die Verwendung auch den Components von Angular 2 und wird als Umstiegshilfe gesehen.

Komponenten werden als HTML Erweiterungen betrachtet, analog zu den Direktiven. Beide beschreiben das Verhalten eines kleinen Teils der Single Page Application Website. Erster Unterschied ist, das Komponenten nur als Elemente verwendet werden können. Der Erste Parameter identifiziert das neue HTML Element in der Angular Camel Case Notation. Der zweite Parameter enthält die Optionen und nicht eine Funktion (mit Rückgabeobjekt) wie bei der Direktive.

   1:  angualar.module("App")
   2:  .component(name, options);

Folgende Optionen können übergeben werden

controller – Name  der oder Konstructor Funktion
controllerAs – Controller Alias
template – html Zeichenkette oder als Funktion die eine html Template Zeichenkette zurück gibt
templateUrl – Zeichenkette oder Funktion die auf eine HTML Datei verweist
bindings – JavaScript Object {} Bindungen zwischen DOM Attributen und den Component Eigenschaften des Component Controllers
transclude – innere ersetzung des HTML Templates mit HTML aus Template Referenzierung (bool)
$... – {function()=} – Factory Funktion

 

Als nächstes ein Beispiel einer Angular Component. Der Wert des HTML Attributes count wird im lokalen scope des Controllers zugewiesen. Der Controller zeigt auf eine inline Funktion, die eine Methode plus bereit stellt. Im Template wird in der Notation Komponenten Name . Controller Eigenschaft/Methode die Bindung an das Viewmodel deklariert.

   1:  .component('counter', {
   2:          bindings: {
   3:            count: '@'
   4:          },
   5:          controller: function() {
   6:            this.plus = function {
   7:              this.count++;
   8:            };
   9:          },
  10:          template: '<div><input type="text" ng-model="counter.count">
<button type="button" ng-click="counter.plus();">+</button></div>'
  11:    })

In der Praxis wird wahrscheinlich im HTML Code ein zum View gehöriger Controller, das Viewmodel bereitstellen.  Entsprechend wird dem count Attribut des Counter kein Wert zugewiesen, sondern eine Eigenschaft des Controllers. Hier mit der ControllerAS Syntax als vm bezeichnet.

   1:  <div ng-controller="MainCtrl as vm">
   2:        <h1>Counter</h1>
   3:        <counter count="vm.count"></counter>
   4:      </div>

In Zeile 3 des JavaScript Component Codes wird dann die Bindung mit count :”=” auf die Eigenschaft des Viewmodels durchgereicht. Die ViewModel Eigenschaft Count kann so über vm.count dann in der Sicht Formular weiter gebunden werden.

Angular Directive Link Function Event Binding

Eigentlich komme ich aus keinem AngularJS Training raus ohne das nicht ein Teilnehmer ein auf den ersten Blick seltsame Scope Binding Frage in Zusammenhang mit Direktiven stellt.

Vor einiger Zeit habe ich mir eine Direktive geschrieben, die einen Submit Button um die Sicherheitsabfrage “Wirklich löschen ergänzt?”. Ein Click Counter auf dem Viewmodel Scope zeigt an, ob der Benutzer OK oder Cancel im PopUp Dialog gewählt hat.

   1:   <div ng-app="App" ng-controller="myController">
   2:          clicked {{count}}<br />
   3:          <button type="button" pp-confirm-click="myclick()" pp-confirm-message="Wirklich?">
löschen</button>
   4:      </div>

Der ziemlich knappe Angular JavaScript Code definiert einen Controller für die eigentliche myClick Methode. Zusätzlich wird eine Direktive als Attribut (restrict) definiert, das eine click Methode an den Button hängt.  Um die Umleitung an den Scope zu delegieren, kommt $apply auf dem so referenzierten scope des Controllers zum Einsatz,

   1:   angular.module('App', [])
   2:          .controller('myController', ['$scope', function ($scope)
   3:          {
   4:              $scope.count = 0;
   5:              $scope.myclick = function () {
   6:                  $scope.count++;
   7:              };
   8:          }])
   9:   
  10:          .directive('ppConfirmClick', [ function(){
  11:              return {
  12:                  restrict: 'A',
  13:                     link: function (scope, element, attrs) {
  14:                      element.bind('click', function () {
  15:                          var message = attrs.ppConfirmMessage;
  16:                          if (message && confirm(message)) {
  17:                               scope.$apply(attrs.ppConfirmClick);
  18:                          }
  19:                      });
  20:                  }
  21:   
  22:              }
  23:          }
  24:          ]);

Nun besteht die in diesem Fall akademische Möglichkeit, die direktive um ein HTML Template zu erweitern mit dem Schlüssel Template bzw TemplateUrl im Rückgabe Objekt. Dazu wird es aber auch nötig eventuell einen eigenen und definierten Scope zu nutzen. Eine Bindung im HTML Template auf Werte soll ja nach außen gekapselt werden.

Wenn man nun aber den scope in folgender Form einfügt, kann auch nicht mehr auf eine Methode des Parent Scopes zugegriffen werden.

   1:  .directive('ppConfirmClick', [ function(){
   2:              return {
   3:                  ...
   4:                  scope: { ... },

Um den Scope von Parent auf den aktuellen zu kopieren, stehen für Eigenschaften in der Direktive Anweisungen wie =,@,& zur Verfügung. Das bedeutet, das im Attribut der Nutzung der Direktive gesteuert wird, was an diese als Parameter zur Verfügung gestellt werden soll. In Zeile 3 des HTML Code Blockes eben die Methode myclick(). Nun kommt das & Steuerzeichen zum Einsatz, das für Methodennamen genutzt wird und erzeugt so im privaten Scope der Direktive eine Referenz auf die Methode. Diese kann dann per Apply im scope angestoßen werden.

   1:   scope: { ppConfirmClick: '&' },
   2:   link: function (scope, element, attrs) {
   3:                   element.bind('click', function () {
   4:                     var message = attrs.ppConfirmMessage;
   5:                     if (message && confirm(message)) {
   6:                            scope.$apply(scope.ppConfirmClick);

UDP Server und Client

Aktuell unterrichte ich an einer IT Schule Objekt Orientierte Programmierung mit C#. Dabei bin ich dauernd auf der Suche nach C# Beispielen, die anhand einer realen praktischen Anwendung ein OO Konzept zeigt. Dieses Mal habe ich vor Socket Kommunikation zu zeigen. Eine Client Server Anwendung auf Low Level. Für den Server wird ein lang laufender Task gestartet, der asynchron läuft. Mit dem Using Schlüsselwort wird ein UDPClient aus dem .NET Framework initiert um auf Port 2000 zu lauschen. Für die Synchronisierung mit dem UI Thread wird die Dispatcher Klasse benötigt.

   1:  Task.Run(async () =>
   2:              {
   3:                  using (var client = new UdpClient(2000))
   4:                  {
   5:                      while (true)
   6:                      {
   7:                          var udp = await client.ReceiveAsync();
   8:                          string txt = Encoding.ASCII.GetString(udp.Buffer);
   9:                          Application.Current.Dispatcher.Invoke(() =>
  10:                          {
  11:                              listView1.Items.Add(txt);
  12:                          });
  13:                      }
  14:                  }
  15:              });

 

Dazu wird ein Client programmiert, was fast noch einfacher von der Hand geht. UDP ist ein schlankes verbindungsloses Protokoll. Hier wird ein einfacher Broadcast ausgelöst auf den auch mehr als ein Server lauschen können.

   1:    using (UdpClient client = new UdpClient())
   2:              {
   3:                  IPEndPoint ipe = new IPEndPoint(IPAddress.Broadcast, 2000);
   4:                  byte[] bytes = Encoding.ASCII.GetBytes("Hello Worlds");
   5:                  client.Send(bytes, bytes.Length, ipe);
   6:              }

MVVM in Json Datei schreiben/lesen

Im folgenden Walkthrough Lab wird eine gebundene Liste auf Benutzerinteraktion als JSON seralisiert gespeichert und gelesen.

Mit Visual Studio 2015 neues WPF Projekt anlegen mit dem Namen MMVMJson. Dem Projekt eine Klasse Person.cs hinzufügen. Mit Visual Studio in der Klasse [PROP] +[TAB] +[TAB] drücken um ein neues Property anzulegen. Mit [TAB] bewegt man sich durch die hervorgehobenen Felder (int – myProperty)

properties

folgende Properties mit Typ erzeugen

ID int

VorName String

FamName String

Eine neue Klasse erstellen mit dem Namen chefCommand.cs mit folgendem Code

   1:   class chefCommand : ICommand
   2:      {
   3:          public event EventHandler CanExecuteChanged;
   4:   
   5:          public bool CanExecute(object parameter)
   6:          {
   7:              return true;
   8:          }
   9:          private readonly Action _action;
  10:          public chefCommand(Action action)
  11:          {
  12:              _action = action;
  13:              
  14:          }
  15:          public void Execute(object parameter)
  16:          {
  17:             _action();
  18:          }
  19:      }

 

In der Zeile 1 wird das Schlüsselwort ICommand rot unterwellt. Den Mauscursor auf das Wort clicken. [STRG]+[.] drücken und [RETURN]. Damit wird die Zeile using System.Windows.Input eingefügt.

Dem Projekt eine neue Klasse mit dem Namen PersonenViewModel.cs hinzufügen. Der Klasse wir ein Property vom Typ ObservableCollection von Person hinzugefügt.

   1:   private ObservableCollection<Person> pListe;
   2:   public ObservableCollection<Person> PListe   
   3:         {
   4:              get { return pListe; }
   5:              set { pListe = value; }
   6:          }

Auch hier werden die unbekannten Typen vom Visual Studio Editor rot unterwellt.

image

Die nötige Zeile using System.Collections.ObjectModel; wird per Autokorrektur [STR]+[.] eingefügt.

Im Konstruktor der Klasse wird für die Namen Hannes Preishuber, Bill Gates, Steve Jobs und Larry Ellison je ein Eintrag zur generischen Liste pListe hinzugefügt.

Zunächst wird der Eigenschaft pListe eine leere Personenliste zugewiesen (Zeile 3). Dann wird pro Person ein neues Objekt vom Typ Person instanziert und die Eigenschaften direkt zugewiesen (Zeile 4)

   1:   public personenViewModel()
   2:          {
   3:              pListe = new ObservableCollection<Person>();
   4:              pListe.Add(new Person { ID = 1, FamName = "Preishuber", VorName = "Hannes" });
   5:  .....

 

Im folgenden wird ein Routed Command für das Speichern der Daten in einer Datei erzeugt. Im ersten Schritt wird per NuGet Paket Manager die Bibliothek JSON.NET dem Projekt hinzugefügt.

image

In der Klasse PersonenViewModel wird dann die Funktion saveList erzeugt und mit folgenden C# Code zum serialisieren der Liste und zum schreiben der Textdatei eingetippt.

   1:   private void saveList()
   2:          {
   3:              JsonSerializer serializer = new JsonSerializer();
   4:              using (StreamWriter sw = new StreamWriter("pliste.json"))
   5:              {
   6:                  using (JsonWriter writer = new JsonTextWriter(sw))
   7:                  {
   8:                      serializer.Serialize(writer, PListe);
   9:   
  10:                  }
  11:              }
  12:          }

Visual Studio wird einige unbekannte Objekte rot unterwellen

image

Mit [STRG] +[.] werden diese Fehler von oben nach unten korrigiert und damit using Codezeilen für Newtonsoft.Json und System.Io erzeugt.

Als letzten Schritt wird ein Bindbares Property erzeugt, das auf die SaveList Methode verweist.

   1:    public ICommand saveCommand
   2:          {
   3:              get { return new chefCommand(saveList); }
   4:          }

Für das Interface ICommand muss using System.Windows.Input eingefügt werden.

Nun wird die Datei MainWindow.XAML geöffnet. Aus der Werkzeugleiste werden 2 Buttons und ein DataGrid auf das Formular gezogen.

image

Wechseln Sie im Editor in die XAML Ansicht. Innerhalb des Window Element und vor dem öffnenden <Grid> fügen Sie folgenden Code ein.

   1:   <Window.Resources>
   2:          <local:personenViewModel x:Key="pvm1"></local:personenViewModel>
   3:      </Window.Resources>

Im Editor wird nach tippen von local: die Klasse von Intellisense vorgeschlagen. Per Tab Taste wird der Vorschlag eingefügt. Da das Projekt nicht kompiliert ist, unterwellt der Editor den Ausdruck blau.

image

Wählen sie im Menü Projekt –Erstellen. Die unterwellung verschwindet dann.

Noch immer im XAML Code wird dem obersten UI Element, hier Grid das deklarativ instanzierte Objekt pvm1 dem Attribut DataContext zugewiesen.

   1:   <Grid DataContext="{StaticResource pvm1}">

Nun kann auf die Eigenschaften des Viewmodels gebunden werden. Der Liste von Personen an das DataGrid und der Save Aufruf an den Button.

   1:  <DataGrid  ItemsSource="{Binding PListe}"
   2:   .../>
   3:  <Button   Command="{Binding saveCommand}" ...

Der Editor zeigt nun die Daten im Designer von Visual Studio an.

image

Starten Sie das Programm mit F5, und ändern Sie die erste Zeile auf Ihren Namen. Drücken Sie Save. Beenden Sie den Debug modus und damit das Programm.

Clicken Sie im Visual Studio Projekt recht um das Context Menü zu öffnen und wählen Sie “Ordner im Datei Explorer öffnen” – Dieser Menüpunkt ist recht weit unten. Wählen Sie das Verichnis BIN-DEBUG

image

Öffnen sie die Datei pliste.json mit einem Editor.

Der Name in der Datei muss der von Ihnen im ausgeführten Programm eingetragene sein. Schliessen Sie die Datei.

In der Datei PersonViewModel.cs wird im Visual Studio Code Editor der Konstruktor der Klasse geändert. Die Zeilen beginnend mit pListe.Add werden ausdokumentiert. Dazu werden die vier Zeilen markiert und die Tastenfolge [STRG]+[K] STRG Halten und dann [C] gedrückt.

image

Als nächstes wird im ViewModel die Methode implementiert um die Json Daten zu laden, zu deserialsieren und dem Property PListe zuzuweisen.

   1:    private void loadList()
   2:          {
   3:              JsonSerializer serializer = new JsonSerializer();
   4:              using (StreamReader sr = new StreamReader("pliste.json"))
   5:              {
   6:                  JsonTextReader reader = new JsonTextReader(sr);
   7:                  pListe = serializer.Deserialize<ObservableCollection<Person>>(reader);
   8:              }
   9:          }

Das Property vom Typ ICommand delegiert den Aufruf an die Methode. Fügen sie dieses in die Klasse PersonenViewModel ein.

   1:    public ICommand loadCommand
   2:          {
   3:              get { return new chefCommand(loadList); }
   4:          }
   5:      

Im Attribut Command des Buttons mit der Beschriftung Save, wird das Binding dem Namen des Propertys zugewiesen in der Form {Binding loadCommand}.

Führen Sie das Programm it F5 aus und drücken sie den Load Button. Die Liste wird nicht erscheinen. Wechseln sie zu Visual Studio in den Code der Klasse PersonViewModel uns setzen sie einen BreakPoint mit F9 auf folgende Zeile

image

Drücken sie im laufenden Programm nochmals den Load  Button. Der Debugger stoppt und zeigt die Codesequenz

image

Drücken Sie F11 um einen Einzelschritt auszuführen. Bewegen Sie die Maus auf die Variable pListe und untersuchen Sie den Inhalt der Variablen pListe.

debug

Das laden war erfolgreich, allerdings nicht die Aktualisierung des User Interfaces. Stoppen Sie das Programm.

Ändern Sie den Code und fügen über einen Iterator jeden Eintrag einzeln zur Collection hinzu.

   1:      var l = serializer.Deserialize<ObservableCollection<Person>>(reader);
   2:                  foreach (Person p in l)
   3:                  {
   4:                      pListe.Add(p);
   5:                  }

Starten Sie das Programm wieder mit F5 und laden die Liste. Diesesmal wird diese angezeigt.

C# MVVM simple Lab

 

Visual Studio 2015 neues WPF Projekt anlegen. Ziel ist es eine WPF View mit dem MVVM Entwurfsmuster mit Logik zu verbinden.

image

Viewmodel Klasse erstellen

dem Projekt Klasse hinzufügen mit dem Namen StarterViewModel.cs. Dies stellt das Viewmodel dar. Die Klasse bekommt nun eine Property Zahl vom Standard Datentyp Int die per Getter und Setter gelesen oder geschrieben werden kann.

In der Klasse tippst du propfull [TAB] [TAB]. Per Tab durch die markierten Felder navigieren. Dabei die interne Variable zahl (klein) nennen und die externe Zahl (gross).

propfull

Um dem später erzeugten Objekt die Möglichkeit zu geben, das UI über Änderungen zu informieren wird das Interface INotifyPropertyChanged implementiert. Nach dem Klassennamen –getrennt durch einen Doppelpunkt –wird das Interface getippt. Visual Studio unterwellt den Namen rot. Das Property benötigt den Namensraum System.Componentmodel. Visual Studio schlägt per [STRG] + [.] die nötige using Direktive vor und inkludiert diese auf [RETURN].

image

Die  Codestelle INotifyPropertyChanged ist dann noch immer rot unterwellt, da das Interface ein konkrete Implementierung vorschreibt. Dies ist in diesem Fall das Event PropertyChangedEventHandler.

image

Es befindet sich nun folgende zusätzliche Zeile Code in der Klasse. Der Access Modifier ist Public um das Event außerhalb des Objektes nutzen zu können.

   1:   public event PropertyChangedEventHandler PropertyChanged;

In der Praxis wird das Event im Viewmodel gekapselt um eine leichtere und wiederverwendbare Handhabung zu haben. Folgende C# Code in die Viewmodel Klasse kopieren.

  protected void OnPropertyChanged(string name)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(name));
            }
        }

Im Setter der Property Zahl wird nach Zuweisung des internen Feldes zahl, das Event ausgelöst, indem die Methode OnPropertyChanged mit dem String Parameter, Name des Propertys, aufgerufen wird.

image

XAML View definieren

Die Datei MainWindow.xaml wird in Visual Studio geöffnet. In der Design Ansicht wird aus der Werkzeugleiste von Visual Studio je ein Button, TextBox und TextBlock Steuerelement auf das Formular gezogen.

image

Als nächstes wird in die XAML Code Ansicht gewechselt. Über das Attribut xmlns ist bereits von Visual Studio der Namensraum local vorbelegt der auf die Projektklassen verweist.

Tippen Sie <Windows.Resources> unterhalb des öffnenden Window Elements. Dann tippst du <l. Intellisense schlägt <local vor. Bestätigt wird per TAB. Als nächstes schlägt Intellisense die vorhandenen Klassen vor,  wähle das Viewmodel aus.

image

Dann wird der Name des so erzeugten Objektes vom Typ StarterViewModel mit dem Attribut x:Key als vm1 definiert. Das deklarativ erzeugte Objekt ist ident zu einem per new Operator im Code erzeugten.

image

Die Verbindung zwischen View und Viewmodel wird per Attribut DataContext eines XAML UI Elements hergestellt. Am einfachsten erfolgt dies auf oberster Ebene des XAML Trees und damit dem Grid Layout Element. Dem Attribut wird der Name des ViewModel Objektes VM1 zugewiesen. Dies erfolgt über {} und innerhalb einer Markupextension StaticResource.

datacontext

Der DataContext gilt für alle untergeordneten Elemente.

Die Eigenschaften Text (DependencyObject) der Kind Elemente Textblock und TextBox werden an das Property Zahl aus dem Viewmodel Objekt gebunden. Auch das geschieht mit einer Markup Extension, dieses Mal mit dem Binding Schlüsselwort.

   1:  Text="{Binding Zahl}"

Das Programm wird mit F5 gestartet. Wenn der Benutzer in das Textfeld die Zahl 1 eintippt und per TAB den Fokus verliert, wird die Bindung aktualisiert. Das Property Zahl enthält dann den neuen Wert, über den Setter der Klasse wird das Event ausgelöst. Der Textblock ist event Subscriber und aktualisiert adhoc die Anzeige.

image

Um nach jedem Tastendruck das Binding zu aktualisieren wird in XAML das Binding um zusätzliches Attribut ergänzt. Nur für die Textbox wird folgender Code ergänzt.

   1:  Text="{Binding Zahl,UpdateSourceTrigger=PropertyChanged}" 

Converter

Die Anzeige soll nun auf Wort statt Ziffer geändert werden, für 1 wird “Eins” angezeigt. Dazu wird eine neue Klasse dem Projekt hinzugefügt mit dem Namen zahlConverter.cs.

Die Klasse wird nach dem : um das Interface IValueConverter erweitert. Mit STR+ . wird der Namensraum per using System.Windows.Data eingebunden. Wieder per STR + . wird das Interface implementiert. Es sind dann die beiden Methoden Convert und ConvertBack in der Klasse vorhanden.

image

Für dieses Beispiel wird nur die Konvertierung von Zahl nach Wort benötigt. Ergänze die Methode Convert wie folgt.

   1:  public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
   2:          {
   3:              switch ((int) value)
   4:              {
   5:                  case 0:return "null";
   6:                  case 1: return "eins";
   7:                  case 2: return "zwei";
   8:                  case 3: return "drei";
   9:                  case 4: return "vier";
  10:                  case 5: return "fünf";
  11:                  case 6: return "sechs";
  12:                  case 7: return "sieben";
  13:                  case 8: return "acht";
  14:                  case 9: return "neun";
  15:              }
  16:              return "non";
  17:          }

 

Der ValueConverter wird ebenfalls deklarativ in XAML instanziiert und mit x:Key cv1 benannt.image.

Der Textblock erhält mit dem zusätzlichen Attribut Converter, innerhalb der Binding Deklaration das Converter Objekt zugewiesen. Da dieses statisch ist mit dem Keyword StaticResource.

   1:  Text="{Binding Zahl,Converter={StaticResource cv1}}"

 

image

Button Command

Um ohne Code Behind auszukommen und auf Daten des Viewmodels zugreifen zu können, muss das Button Click Event in der Viewmodel Klasse behandelt werden. Zuerst wird eine Klasse benötigt, die sich um die Delegation des Events kümmert. Diese muss das ICommand Interface implementieren.

Ausgehend vom einem Chef, der nichts selber macht, sondern auf Zuruf delegiert wird eine Klasse chefCommand.cs dem Projekt hinzugefügt.

image

Nach dem Klassennamen wird : und der Interfacename ICommand getippt. Per STR+ . wird per Using der Namensraum eingefügt. Per weiteren STR + .  Tastatur Kommando wird das Interface bzw die benötigten Methoden implementiert.

image

Entferne in der Methode CanExecute die Exception und schreibe return true;

Zusätzlich wird ein Readonly Field vom Typ Action definiert. Im Konstruktor der Klasse wird die Aufzurufende ViewModel Methode als Parameter vom Typ Action übergeben.

Im der Execute Methode wird dann die so übergebene ViewModel Methode aufgerufen.

   1:   private readonly Action _action;
   2:          public chefCommand(Action action)
   3:          {
   4:              _action = action;
   5:              
   6:          }
   7:          public void Execute(object parameter)
   8:          {
   9:             _action();

Nun wird wieder in der Datei StarterViewModel.cs eine Methode machsieben hinzugefügt. Diese setzt das private Feld auf zahl auf den Wert 7. Um das User Interface bzw. die Eigenschaften Text adhoc zu aktualisieren muss das Event PropertyChanged an alle Subscriber gesendet werden.

   1:   private void machsieben()
   2:          {
   3:              zahl = 7;
   4:              OnPropertyChanged("Zahl");
   5:              
   6:          }

Das XAML Button Command kann nur per Property vom Typ ICommand gebunden werden, das im letzten Schritt im ViewMode Code ergänzt wird. Der Getter des Propertys liefert eine Instanz der Chefklasse, mit den Namen der Viewmodel Methode.

   1:     public ICommand machsiebenCommand
   2:          {
   3:              get { return new chefCommand(machsieben); }
   4:          }

Im XAML WPF Code wird in Button das Attribut Command dem Binding zugewiesen.

image

Mehr Infos auf der Seiten von Microsoft.

IIS Custom Request Header Logging

Im Zuge der Umstellung der ppedv.de Website auf Bootstrap und responsive Design, wollen wir herausfinden welche Seiten von den Nutzern aufgerufen werden.

Der Umstieg folgt den agilen Prinzipien und wird während des laufenden Betriebs durchgeführt. Es handelt sich dabei um tausende einzelseiten, die zumeist überhaupt nicht verlinkt sind, sondern nur per Suchmaschine angesteuert werden. Wesentliche Änderung ist eine neue Masterpage, die jeder einzelnen Content Page zugewiesen wird.

Der Internet Information Server schreibt recht detailliert die Zugriffsdaten in Logfiles. Im IIS Manager lässt sich in den Logging Einstellungen ein neues Feld, (Custom Field) hinzugefügt werden.

image

In die Masterpage Alt wird eine Zeile Code im Page Loaded Event eingefügt, die den HTTP Antwort Header beschreibt.

   1:    HttpContext.Current.Response.AppendHeader("ppedv", "ppedvalt")

Im Logfile erscheint der neue Eintrag im Header, wenn die Website durchgestartet wird.

#Software: Microsoft Internet Information Services 8.5
#Version: 1.0
#Date: 2015-11-12 19:53:10
#Fields: date time s-ip cs-method cs-uri-stem …… ppedvalt

Per Logparser lassen sich dann Einträge auswerten, die den Wert ppedvalt im Feld ppedvalt enthalten.

2015-11-12 19:58:53 148.251.193.237 GET /Schulung/Quicky.aspx – 80 …. ppedvalt

So lassen sich Schrittweise die meist genutzen Webseiten finden und umstellen.

Windows Server 2016 Training

Month List