1 Ziel, Anforderungen und verwendete Technologien
Bevor man beginnt etwas zu programmieren, sollte man sich möglichst genau im Klaren sein, was das letztendliche Ziel ist, da der Umbau eines Programms enorm aufwendig sein kann.
Ich möchte ein Programm erstellen, mit dem ich meine Dateien verwalten kann. Zwar kann man mit Hilfe einer sinnvollen Ordnerstruktur einen guten Überblick behalten, allerdings wünsche ich mir zusätzlich die Funktion Dateien zu taggen. Wenn ich also z.B. ein Lied vom Sänger A habe, an welchem der Sänger B mitgewirkt hat, und das Lied im Ordner mit dem Namen "Sänger A" liegt, dann soll ich das Lied mit "Sänger B" taggen können, sodass ich es leicht finden kann.
Das Programm werde ich mit WPF erstellen, das heißt es wird C#- und XAML-Code verwendet.
Ich setze für diesen Kurs ein gewisses Grundwissen vorraus, du solltest mindestens die Artikel in der Rubrik Grundkonzepte gelesen und verstanden haben.
Die Unterschiede zwischen Java und C# sind nicht sonderlich gravierend, die Syntax ist fast identisch, lediglich einige Funktionalitäten und Schlüsselwörter sind verschieden.
Anmerkung
Ich setze öffnende geschweifte Klammern immer in die selbe Zeile, wie den Kopf, da ich persönlich es als übersichtlicher empfinde. Am besten probierst du aus, was dir besser gefällt. Sollte es dir egal sein, dann setz die Klammern am besten in die nächste Zeile, wie es auch die meisten C#-Programmierer tun.
2 Projekt erstellen
Zuerst solltest du dir Visual Studio herunterladen, ich werde meine Beispiele an Visual Studio 2015 ausrichten.
Sobald du Visual Studio geöffnet hast, erstelle ein neues Projekt (WPF-Application) mit einem aussagekräftigen Namen, z.B. "DateiverwaltungPro".
Die Ordnerstruktur
Rechts in deinem Fenster sollte nun ein Panel sein, welches in etwa folgendermaßen aussieht:
Es gibt folgende Elemente:
Die Solution (1) und das Projekt (2) beinhalten die eigentlichen Dateien, eine Solution kann auch mehrere Projekte beinhalten.
Die Properties (3) und die App.config (5) interessieren uns erstmal nicht. Bei den References (4) können wir dll's einbinden, sodass wir Code von anderen Leuten verwenden können.
Die App.xaml (6) ist der Einstiegspunkt des Programms und die Datei MainWindow.xaml (7) ist das Fenster, welches als erstes gezeigt wird.

XAML
Wir betrachten die Datei App.xaml, wo unser Programm beginnt.

Die Struktur des Codes ist wie in XML, es gibt Elemente und Attribute. Ein Element ist zum Beispiel <Application />.
x:Class="DateiverwaltungPro.App" hingegen ist ein Attribut. Folgende zwei Elemente sind identisch.
Die zweite Schreibweise ist nötig, wenn das Element Kindelemente haben soll.Das Attribut StartupUri="MainWindow.xaml" gibt an, welche View zuerst angezeigt wird. Die App.xaml Datei werden wir nur selten bearbeiten. Bevor wir uns der MainWindow.xaml zuwenden, müssen wir zuerst noch einen Happen Theorie ins Spiel bringen.
3 MVVM
Das sogenannte Model-View-ViewModel Modell beschreibt eine Vorgehensweise, welche unter anderem bei WPF verwendet wird.
Die View ist eine XAML Datei, also zum Beispiel MainWindow.xaml. In dieser Datei wird festgelegt wie die Oberfläche auszusehen hat. Das ViewModel ist hingegen eine C# Quellcode Datei, in der die Logik und die Objekte stecken, wir werden dieses nachher erstellen. Das Model sind die Daten, also ein Objekt.
Beispiel
Nehmen wir an, wir würden eine Kontaktverwaltung schreiben, wo wir Personen mit ihren Anschriften und ihren Kontaktdaten speichern möchten. Wir hätten in der Oberfläche vermutlich eine Liste mit Namen und wenn man eine Person anklickt, würden alle Daten zu dieser Person angezeigt.
Wir würden dann eine View erstellen ContactView.xaml, welche Textfelder für Name, Adresse und Telefonnummern beinhaltet. Die Daten des Kontaktes wären in einer Instanz der Klasse Contact.cs festgehalten, was wir beim MVVM als Model bezeichnen. Die beiden Dateien werden durch das ViewModel ContactViewModel.cs verknüpft. Dieses beinhaltet die Instanz des Kontaktes und diverse Methoden, z.B. zum Speichern oder Löschen des Kontaktes. Die View kann auf das ViewModel zugreifen und so den Namen des Kontaktes anzeigen.
In diesem Programm würden wir also, wenn eine Person in der Liste ausgewählt ist, eine View mit einem ViewModel, welches genau diese Person als Contact beinhaltet, anzeigen.
Ich werde später, wenn wir diese Dinge haben, nochmal darauf zurückkommen, sodass du leichter verstehst, wie genau das Ganze im Programm zusammenwirkt.
Vorteile
MVVM ist extrem nützlich, wenn man in größeren Teams arbeitet. Die Designer können eine Oberfläche entwerfen, während die Programmierer an Models und ViewModels arbeiten. Wenn die "schöne" Oberfläche dann fertig ist, kann sie eingetauscht werden. Es gibt auch noch Vorteile beim Testen und MVVM zeichnet sich durch eine relativ übersichtliche Projektstruktur aus.
4 ViewModel 1/2
Zuerst bringen wir etwas Struktur in unser Projekt. Erstelle einen Ordner "Views" im Projekt und verschiebe die MainWindow.xaml-Datei dort hinein.
Zusätzlich benennen wir die Datei zu MainWindowView.xaml um. Das kannst du im Solution Explorer mit einem Rechtsklick machen.Jetzt müssen wir ein paar Dinge anpassen. Öffne die Datei MainWindowView.xaml.cs indem du im Solution Explorer die Datei MainWindowView.xaml aufklappst und die darunter liegende Datei anklickst.Diese Datei nennt man den "Code-behind", sie wird bearbeitet, wenn man Dinge in der View einbauen will, die mit XAML allein nicht möglich sind, z.B. Drag & Drop. Da wir in der MainWindowView.xaml schon angegeben haben, dass es sich um ein Fenster handelt, ist es nicht nötig, dass die Klasse MainWindowView.xaml.cs von Window erbt, ändere diese Datei, dass sie in etwa folgendermaßen aussieht:
Sollte der Code Fehler anzeigen, so liegt dies daran, dass wir auch an anderer Stelle Anpassungen vornehmen müssen. Öffne die Datei MainWindowView.xaml. Das oberste Element, das Window beinhaltet ein Attribut mit dem Namen x:Class, ändere den Wert auf DateiverwaltungPro.Views.MainWindowView. Zur Info: dieses Attribut gib an, wo die Code-behind Klasse zu finden ist.
Zuletzt müssen wir in der App.xaml auch noch angeben wo unsere MainView jetzt zu finden ist.
Wenn du oben in der Ribbon jetzt auf den Start-Button mit dem grünen Pfeil klickst, sollte die Anwendung wieder kompilieren.
Das ViewModel
Erstelle im Views-Ordner eine C# Klasse mit dem Namen MainWindowViewModel.cs.
Es ist eigentlich nicht notwendig, dass das ViewModel im gleichen Verzeichnis liegt, wie die View und dass der Name "…Model" lautet, also fast gleich wie die View, jedoch ist es für einige Frameworks wichtig. Am besten gewöhnst du dir das also gleich an.
Bevor wir das ViewModel nun füllen können, schauen wir uns Properties an.
5 Properties
Wenn Daten in einer Klasse gespeichert werden sollen, können in C# Felder oder Properties verwendet werden.
Felder
Dir sollten Felder bereits bekannt sein, :
namespace DateiverwaltungPro.Views { public class MainWindowViewModel { public int ButtonClicksAmount; }}
In diesem Beispiel ist ButtonClicksAmount public, d.h. von überall her kann darauf zugegriffen werden. Wenn wir nun bestimmte Einschränkungen vorgeben möchten, müssen wir das Feld als private definieren und einen Getter und einen Setter schreiben.
Um diesen Kurs etwas interessanter zu gestalten werde ich ab sofort möglichst viele Aufgaben integrieren.
Aufgabe 1
Ändere die Sichtbarkeit der ButtonClicksAmount-Variable auf private und erstelle einen Getter und einen Setter. Folgende Bedingungen sollen eingehalten werden:
Die Variable soll keine negativen Werte zugewiesen bekommen.
Wenn der Wert größer als 1000 ist, soll 1000 zurückgegeben werden.
Private Felder werden i.d.R. beginnend mit einem Unterstrich und einem Kleinbuchstaben geschrieben. Parameter und andere lokale Variablen werden klein geschrieben.
Da in WPF relativ oft Logik im Getter oder Setter benötigt wird, hat man nur selten Felder, welche keinen Getter oder Setter benötigen. Um den Code trotzdem möglichst kompakt und übersichtlich zu halten, wurden Properties entwickelt.
Properties
Das Äquivalent zum Feld public int ButtonClicksAmount; lässt sich auf zwei Arten schreiben:
// Die kompakte Versionpublic int ButtonClicksAmount{ get; set; }
// Mit einem so gennanten 'backing field'private int _buttonClicksAmount;
public int ButtonClicksAmount { get { return _buttonClicksAmount; } set { _buttonClicksAmount = value; }}
Die ausführliche Version wird benötigt, um Logik im Getter oder Setter unterzubringen. Die Syntax um auf den Wert zuzugreifen ist gleich wie bei einem Feld:
ButtonClicksAmount = 42;
Aufgabe 2
Ändere deinen Code so um, dass alles von Aufgabe 1 mit einer Property umgesetzt ist.
Jetzt muss nicht mehr umständlich ein Getter oder Setter aufgerufen werden.
6 View
Gehe in die MainWindowView und öffne die Toolbox, indem du im Menü View - Toolbox auswählst. Wenn du oben in der Leiste der Toolbox auf die Stecknadel klickst, wird jene angeheftet.
Such nun nach dem Button und dragge ihn in den Designer. Das Ergebnis sollte in etwa wie folgt aussehen:
Wenn du nun einen Blick in den XAML Code auf der rechten Seite, bzw. unter dem Designer wirfst, wirst du festellen, dass ein Button-Element erstellt wurde.Selbstverständlich kannst du einen neuen Button auch direkt im XAML-Code anlegen.
Ich würde dir raten, den Designer und den XAML-Code nebeneinander anzuzeigen, du kannst dies mit den Buttons zwischen den beiden Ansichten umschalten, du findest sie ganz rechts bzw. unten.
Über Tools(Menüleiste) - Options(ganz unten) - XAML Designer(auch ganz unten) kannst du bei dem Punkt Split Orientation auch einen default Wert angeben, sodass du dies nicht immer manuell umschalten musst.
Der Übersichtlichkeits halber ordne ich die Attribute eines XAML-Elements immer untereinander an.
Aufgabe 1
Modifiziere den Button so, dass folgende Punkte erfüllt sind:
In dem Button steht "Klick mich :)"
Der Button hat die Maße 120 * 25
Der Button ist genau in der Mitte
Das Attribut x:Name sorgt übrigens dafür, dass ein Element einen eindeutigen Namen bekommt, mit welchem wir dieses im Code-behind ansprechen können.
Anordnung von Elementen
Das oberste Element in dieser View ist ein Window; dieses kann nur ein Kind haben, welches idR. ein Grid ist. Es gibt auch noch andere Elemente, die nur ein Kind haben können, ein Grid hingegen kann beliebig viele Kinder haben.
Aufgabe 2
Lösche den Button
Erstelle in deinem Grid ein weiteres Grid
Platziere in diesem Grid einige Buttons, sodass es wie der Nummernblock rechts auf der Tastatur aussieht
(Bonus) gib dem Grid einen hellgrauen Hintergrund und mach es schön.
Tipps:
Du kannst in einem Grid Reihen und Spalten definieren:
Diese beiden Elemente musst du ins Grid packen. Eine Spalte mit Auto nimmt sich so wenig Platz wie nötig, eine Spalte mit * hingegen soviel wie möglich. 2* und 3* sorgen für ein Verhältnis von zwei zu drei. In den Elementen im Grid musst du dann noch angeben, in welche Reihe und Spalte sie gehören, das tust du mit den Attributen Grid.Row="2" und Grid.Column="3". Bedenke, dass man in der Informatik bei 0 anfängt zu zählen. Soll ein Element mehr als eine Reihe bzw. Spalte umfassen, z.B. zwei, so kannst du zusätzlich das Attribut Grid.RowSpan="2" bzw. Grid.ColumnSpan="2" angeben.
Mit dem Attibut Margin lassen sich Abstände nach außen, mit Padding nach innen definieren. Gib eine Zahl für einen gleichmäßigen Abstand oder zwei, mit Kommas getrennnte, Zahlen für den horizontalen und vertikalen Abstand an. Wenn du vier Zahlen angibst, so stehen diese für individuelle Abstände (links, oben, rechts, unten).
Es gibt selbstverständlich verschiedene Möglichkeiten dies umzusetzen. Wenn du z.B. nur mit Margin und ohne Column- und Row-Definitions gearbeitet hast, dann wäre es umständlicher, den Abstand auf z.B. 15 zu erhöhen.
Bei XAML wird bei Größenangaben übrigens nicht in Pixeln gerechnet, damit das Ergebnis auf verschiedenen Bildschirmen mit unterschiedlicher Pixeldichte (dpi) möglichst gleich aussieht, die Größenordnung ist aber in etwa die Selbe. Du könntest dem Window z.B. auch die Höhe 10cm verpassen.