Blockchain – Teil 1: Einführung

In dieser Artikelserie wird das Thema Blockchain von der technischen Seite betrachtet und außerdem Anregungen und Beispiele zum Thema Programmieren mit der Blockchain geboten. Vielleicht nicht für die absoluten Anfänger geeignet, aber wer sich für eine Sache wirklich interessiert oder etwas wirklich will, kann es auch schaffen.

Was ist die Blockchain?

Eine Blockchain wurde als erstes für die Umsetzung einer digitalen Währung, einer sogenannten Kryptowährung, und zwar mit dem Bitcoin umgesetzt. Aktuell arbeiten allerdings immer mehr Unternehmen und Institutionen in anderen Anwendungsbereichen an eigenen Blockchain Umsetzungen. Als Referenz Implementation für die folgende Erklärung dient der Bitcoin, natürlich kann sich die Umsetzung bei anderen Applikationen in Details unterscheiden.

Die Blockchain ist eine geordnete zurückverfolgbare Liste von Transaktionsblöcken. Die Blockchain kann als Datei (eine so genannten Flat File) oder auch in einer einfachen Datenbank gespeichert werden. Im Falle von Bitcoin core wird dafür die LevelDB von Google genutzt.

Im Rahmen von Bitcoin wird auch von einem distributed ledger also einem verteilten Hauptbuch gesprochen. Zu jeder Adresse auf der Blockchain werden die Dateneingänge und Ausgänge gespeichert. Im Falle von Bitcoin also die Geldeingänge und Geldausgänge. Was bei der Sendeadresse im Ausgang steht, steht bei der empfangenden Adresse im Eingang.

Die einzelnen Blöcke sind back-linked, also immer mit dem vorherigen Block in der Blockchain verknüpft. Die Blockchain wird oftmals als vertikaler Stapel mit übereinander geschichteten Blöcken dargestellt und der erste Bock dient als Fundament für den gesamten Stapel.

Durch die Darstellung der Blockchain in Blöcken die aufeinander gestapelt sind, entsteht auch der Begriff der Höhe, zum Beispiel einer Transaktion. Hiermit ist der Abstand, zum Beispiel des Blockes einer Transaktion, zum ersten Block den es jemals gab, gemeint.

Jeder Block der Blockchain wird mit einem Hashwert im Header des Blockes identifiziert. Im Falle von Bitcoin wird dafür der SHA256 Algorithmus genutzt, natürlich könnte genauso gut ein anderer Hashalgorithmus genutzt werden. Außerdem gibt es in jedem Blockheader noch ein Feld „previous-block“, dass den Hashwert des vorherigen Blockes enthält, so entsteht die Verkettung, die zurück bis zum allerersten Block den es je gab, dem so genannten Genesis Block, reicht.

Das bedeutet jeder Block hat ganz genau einen Elter, kann aber temporär mehrere Kinder haben, in dem einfach mehrere Nachkommen eines Blockes, den gleichen Hashwert in dem „previous-block“ Feld stehen haben.

Mining

Im Falle von Bitcoin wird so genanntes Mining betrieben um Transaktionen zu überprüfen und zu bestätigen. Dieses dezentrale Clientnetzwerk, also die Miner, bieten den Sicherheitsmechanismus der Blockchain. Sie überprüfen neue Transaktionen auf der Blockchain und speichern diese auf dem Globalen Hauptbuch. In diesem dezentralen Konzept gibt es keine Server, es können jederzeit neue Miner sich dazuschalten oder aber auch offline genommen werden und der Inhalt der Chain wird davon nicht beeinflußt. Es gehen deshalb keine Daten verloren, weil die Miner (bzw alle Full Nodes) eine komplette Kopie der Blockchain gespeichert haben.

Ein neuer Block der alle neuen Transaktionen seit dem letzten Block enthält wird regelmäßig (bei Bitcoin im Durchschnitt alle 10 Minuten) „gemint“ und damit der Blockchain offiziell hinzugefügt. Allerdings müssen alle Miner ein sehr rechenaufwändiges mathematisches Problem (Proof-of-Work) lösen, dass man nur mit durchprobieren aller Möglichkeiten, lösen kann. Das verbraucht viel Rechenleistung, und die Schwierigkeit ist so angepasst, dass dies ca. alle 10 Minuten passiert. Der Miner der das Rätsel lösen konnte, bekommt 12,5 Bitcoins (Stand November 2017) für seinen hohen Rechenaufwand als Entschädigung und die anderen Miner überprüfen und bestätigen, dass der Gewinner das Rätsel wirklich gelöst hat. Dadurch wird der Block und dann auch die Transaktionen in dem Block auf der Blockchain gültig. Danach beginnt das Spiel von neuem.

Zum Thema Mining gibt es eigentlich noch viel mehr zu sagen und deshalb kann es gut sein, dass dazu auch noch ein Artikel in diese Serie erscheinen wird.

Mit Hilfe eines Blockchain Explorers, ein Beispiel im Bereich Bitcoin ist https://blockchain.info, kann man sich einzelne Blöcke und ihre Transaktionen anschauen.

Bitcoin Transaktion – Quelle: https://blockchain.info

Aber auch einzelne Adressen, an die Daten, zum Beispiel Bitcoins, verschickt werden können, kann man auf dieser Seite eingeben und sehen von welcher Adresse, wann, welche Daten gekommen sind. Man braucht dafür keine Authentifizierung jeder kann diese Daten von jedem zu jeder Zeit abrufen. Da die Adressen aber nicht direkt auf einzelne Personen schließen lassen, ist es noch solange Anonym, solange man seine Adresse nicht irgendwo veröffentlicht. Jedoch kann man beliebig viele neue Adressen generieren, so dass es unwahrscheinlich ist das jemand alle Adressen einer Person herausfinden kann.

Bitcoinadresse – Quelle: https://blockchain.info

Anwendungsbereiche der Blockchain

Da die Blockchain mit Bitcoin groß geworden ist, findet man auch im Kryptowährungsbereich viele andere Coins die ebenfalls mit einer Blockchain umgesetzt wurden, meist aber technische Details verändert haben und somit versuchen eine technisch bessere Umsetzung als der Bitcoin zu bieten. Ein paar Beispiele hierfür sind:

  • Ethereum
  • Litecoin
  • Dash
  • Bitcoincash
  • Monero

Wer glaubt die Blockchain wäre nicht für viele andere Bereiche auch interessant irrt sich. Beispielsweise das amerikanische Unternehmen Visa hat vor kurzem einen Zahlungsdienst mit dem Namen B2B Connect veröffentlicht. Der Dienst soll Direktzahlungen zwischen einzelnen Unternehmen effizienter, sicherer und transparenter umsetzen und basiert auch auf einer Blockchain.

Auch Regierungen beschäftigen sich mit der Blockchain, so hat die Europäische Kommission einen 131 seitigen Bericht vorgelegt in dem die Möglichkeiten zum Einsatz der Blockchain im Bereich Bildung behandelt werden.

Das Thema ist noch relativ jung und viele Unternehmen arbeiten und forschen an dem Thema, es gibt Ideen Dokumente wie Führerscheine und Personalausweise per Blockchain verfügbar zu machen. Andere Ideen sind Klausuren und Abschlussarbeiten an den Universitäten über eine Blockchain zur Verfügung zu stellen und es gibt noch sehr viel mehr Umsetzungen schon jetzt und es werden in Zukunft noch viel mehr werden.

Vor- und Nachteile einer Blockchain

Die folgende Liste beinhaltet die mir aktuell bekannten und wichtigsten Vor- und Nachteile.

VORTEILE

  • Dezentralität – Es gibt keine Server, sondern ein Peer-To-Peer Netzwerk, dadurch ist kein Vertrauen in eine zentrale Stelle, Unternehmen oder Personengruppe nötig
  • Unveränderlichkeit der Daten – Einmal in der Blockchain bestätigte Blöcke, können nachträglich nicht mehr verändert werden, da die nachfolgenden Blöcke auf den vorherigen aufbauen. Würde ein Miner versuchen Blöcke zu verändern, würde es allen anderen Minern auffallen und die ungültigen Daten würden nicht mit in den Chain aufgenommen werden.
  • Sicherer Datenaustausch ohne Mittelsmann möglich – Das kann zum Beispiel der Kauf von jedem beliebigen Produkt oder auch das Versenden von (digitalen) Geld sein, mit der Blockchain ist dafür keine Bank oder ein Zwischenhändler mehr nötig, man könnte somit direkt beim Hersteller kaufen. Bereits jetzt gibt es zahlreiche (online)Shops in denen man mit Bitcoins bezahlen kann. Auch der Transfer von Geld ins Ausland z.B. nach China kann zu jeder Zeit und mit sehr niedrigen Kosten realisiert werden, innerhalb von wenigen Minuten ist das Geld auf der Wallet (Konto) des Empfängers.
  • Hochverfügbarkeit – Je mehr Clients sich in das Netzwerk einloggen umso verfügbarer werden die Daten, ein einzelner Client würde ausreichen um alle Daten zur Verfügung zu stellen. Bei tausenden von Clients um den ganzen Globus verteilt, sprechen wir hier von echter Hochverfügbarkeit. Fallen (im Beispiel von Bitcoin) 100 Clients auf einmal aus, wird es keiner merken, die Blockchain ist weiter verfügbar.
  • Geschwindigkeit – Im Falle von Kryptowährungen kann man auch die Performance angeben, welche Bank bietet schon weltweite Überweisungen an, die innerhalb weniger Minuten auf dem Empfängerkonto sind für ein paar Cents pro Überweisung?

NACHTEILE

  • Rechenaufwand für die einzelnen Clients – Im Falle von Bitcoin ist aktuell ein sehr hoher Rechenaufwand und Stromverbrauch für das „Mining“ nötig. Allerdings hängt der nötige Aufwand auch von der einzelnen Applikation und Implementation einer Blockchain ab und es wird auch hier noch Verbesserungen geben
  • Geschwindigkeit – Die Geschwindigkeit einer Blockchain bzw. die Übernahme der Daten in die Blockchain kann nicht mit der Geschwindigkeit einer zentralisierten Datenbank mithalten.
  • Öffentlichkeit der Daten – Sobald man die Adresse einer Person zuordnen kann zum Beispiel weil die Person die Adresse zu Zahlungszwecken veröffentlicht, kann man auch die Transaktionen der Adresse einer Person zuordnen. Hiergegen gibt es bereits erste Umsetzungen die das Problem versuchen zu beseitigen. Man kann dies auch umgehen in dem man beispielsweise für jeden Zahlung eine eigene Adresse anlegt.

 

Aufbau eines Blocks

Ein Block ist ein Behälter der Transaktionen sammelt, die dann in das distributed ledger (verteilte Hauptbuch) also in die Blockchain übernommen werden.

Der Block hat einen Header der Metadaten enthält. Nach den Metaden folgt eine lange Liste von Transaktionen, diese machen den größten Teil des Blocks aus. Der Block Header ist im Falle von Bitcoin 80 Bytes klein, während die durchschnittliche Transaktion etwa 250bytes und der durchschnittliche Block etwa 500 Transaktionen enthält (Stand Juni 2017 Quelle: Andreas M. Antonopoulous, Mastering Bitcoin). Durch ein Update (mit dem Namen SegWit) der Blockchain sind jetzt allerdings auch größere Blöcke möglich, um die Skalierbarkeit besser zu gewährleisten.
Die folgende Tabelle beschreibt den Aufbau eines Blocks:

Größe Feldname Beschreibung
4 bytes Block Size Die Größe eines Blocks in bytes
80 bytes Block Header Mehrere Felder formen den Block Header (zum Beispiel der Hashwert des vorherigen Blocks)
1-9 bytes Transaction Counter Anzahl der folgenden Transaktionen
Variabel Transactions Die in diesem Block gespeicherten Transaktionen

Quelle: Eigene Darstellung in Anlehnung an die Daten von Andreas M. Antonopoulous, Mastering Bitcoin

Blockheader

Der Blockheader enthält drei Metadatensets. Als erstes gibt es ein Feld mit dem Hash des vorherigen Blocks, das den Block mit dem vorherigen verbindet. Das zweite Set von Daten beinhaltet den Schwierigkeitsgrad (difficulty), einen Zeitstempel und ein Feld für die Lösung des mathematischen Problems, mit dem Namen nonce. Das zweite Set von Daten ist für das mathematische Problem (Proof-Of-Work) gedacht. Das dritte Set von Daten ist der merkle tree root, eine Datenstruktur die genutzt wird um Hashwerte über alle Transaktionen in dem Block zu erstellen. Damit wird gewährleistet, dass die Transaktionen in dem Block nicht verändert werden können, ändert sich auch nur eine Zahl in einer Transaktion, wäre der merkletree Wert ein völlig anderer und es fällt sofort auf.

Größe Feldname Beschreibung
4bytes Version Versionsnummer um Software und Protokollupdates zu verfolgen
32 bytes Previous Block Hash Der Hashwert des vorherigen Blocks in der Blockchain
32 bytes Merkle Root Ein Hashwert vom Anfang des merkle trees erzeugt über die Transaktionen dieses Blocks.
4 bytes Timestamp Die ungefähre Erstellzeit des Blocks (Unixzeitformat)
4 bytes Difficulty Target Die Proof of Work Algorithmus Schwierigkeit für diesen Block
4 bytes Nonce Das Ergebnis des mathematischen Rätsels (Proof-Of-Work)

 

Block identifiers: Block Header Hash und Block Höhe

Ein Block wird hauptsächlich über einen Hashwert identifiziert. Dieser digitale Fingerabdruck wird erstellt in dem der Header des Blocks 2x mit dem SHA256 Algorithmus ausgeführt wird. Das Ergebnis daraus wird der Blockhash genannt, ein passenderer Name wäre Blockheaderhash. Alternativ kann man einen Block mit dem Wert der Blockhöhe identifizieren, der erste Block der jemals erstellt wurde, also der Genesis Block, hat eine Höhe von 0, für die nachfolgenden Blöcke wird diese Zahl einfach hochgezählt.

Netzwerk

Im Bitcoinwhitepaper werden die folgende Schritte für den Ablauf beschrieben.

  1. Neue Transaktionen werden an alle Knoten (also Clients/Peers) verteilt
  2. Jeder Knoten sammelt neue Transaktionen in einem neuen Block
  3. Jeder Knoten arbeitet an dem mathematischen Problem (Proof-of-Work) für diesen Block
  4. Wenn ein Knoten das Problem lösen konnte, verteilt er den Block inklusive der Lösung, an alle anderen Knoten
  5. Die anderen Knoten akzeptieren den neuen Block nur wenn alle Transaktionen in dem Block gültig und nicht bereits ausgegeben sind.
  6. Die anderen Knoten zeigen ihre Akzeptanz des neuen Blocks in dem sie anfangen an dem nächsten Block zu arbeiten. Hierzu nutzen sie den Hashwert des neuen Blocks in dem Feld für den Hashwert des vorherigen Blocks.

 

Dir ist dies alles viel zu oberflächlich und du möchtest gerne mehr und schneller lernen und hast außerdem gute Englischkenntnisse?

Na dann kommst du nicht an folgenden Fachbuch vorbei, ich behaupte es ist eine der besten, wenn nicht die beste, Quelle zu diesem Thema: Mastering Bitcoin

Hast du Fragen, Anregungen oder Artikelwünsche zu diesem Thema? Dann schreibe einfach ein Kommentar dazu.

Escape Sequenzen

Escape Sequenzen werden in einem String genutzt um eine spezielle Funktion auszuführen oder ein sonst unerlaubtes Zeichen innerhalb einer Zeichenkette auszugeben. Dies kann zum Beispiel ein Zeilenumbruch, ein Tabstopp oder das Darstellen von Sonderzeichen sein. Die verschiedenen Programmiersprachen haben hierbei teilweise unterschiedliche Escape Sequenzen.

Eine Escape Sequenz beginnt immer mit einem Backslash „\“ gefolgt von einem oder mehreren Buchstaben oder einer Zahlenkombination.

Folgende Tabelle gibt einen Überblick über die Escape Sequenzen in C#:

Escapesequenz Repräsentiert
\a Glocke (Warnung)
\b Rücktaste
\f Seitenvorschub
\n Zeilenwechsel
\r Wagenrücklauf
\t Horizontaler Tabulator
\v Vertikaler Tabulator
\‘ Einfaches Anführungszeichen
\“ Doppeltes Anführungszeichen
\\ Umgekehrter Schrägstrich
\? Literales Fragezeichen
\ ooo ASCII-Zeichen in der Oktalnotation
\x hh ASCII-Zeichen in der Hexadezimalnotation
\x hhhh Unicode-Zeichen in der Hexadezimalnotation, wenn diese Escapesequenz in einer Konstante mit Breitzeichen oder in einem Unicode-Zeichenfolgenliteral verwendet wird.

Beispielsweise WCHAR f = L’\x4e00′ oder WCHAR b[] = L“The Chinese character for one is \x4e00″.

Quelle: Microsoft

In Java werden auch einige dieser Sequenzen unterstützt, welche kannst du in der folgenden Tabelle erkennen:

Zeichen Repräsentiert
\b Rücktaste
\n Zeilenwechsel
\f Seitenvorschub
\r Wagenrücklauf
\t Horizontaler Tabulator
\“ Doppeltes Anführungszeichen
\‘ Einfaches Anführungszeichen
\\ Backslash

Quelle: Eigene Darstellung

Nehmen wir jetzt mal folgenden Beispieltext:

„Auf der Seite:                  https://lerne-programmieren.com/blog

finde ich viele kostenlose Tutorials und Erklärungen, die mir helfen ein erfolgreicher Programmierer zu werden. Wenn ich etwas nicht direkt finde, nutze ich die Suchfunktion oder schreibe einen Kommentar unter einen Beitrag oder auf der Facebookseite

https://www.facebook.com/IchLerneProgrammieren/

Wenn man diesen Text nun einfach in einem „Console.WriteLine(<String>);“ Befehl kopiert wird diese nicht korrekt dargestellt werden. Es fehlen die Tabstopps und die Zeilenumbrüche deshalb würde es folgendermaßen aussehen:

Quelle: Eigene Darstellung

Wenn wir den Text aber formatieren wollen, müssen folgende Escape Sequenzen genutzt werden:

Console.WriteLine("Auf der Seite:\t\t https://lerne-programmieren.com/blog\r\nfinde ich viele kostenlose Tutorials und Erklärungen, die mir helfen ein erfolgreicher Programmierer\r\nzu werden.Wenn ich etwas nicht direkt finde, nutze ich die Suchfunktion oder schreibe einen\r\nKommentar unter einen Beitrag oder auf der Facebookseite\r\n\n \"https://www.facebook.com/IchLerneProgrammieren/\" ");

Das Ergebnis:

Quelle: Eigene Darstellung

Du willst mehr über Escape Sequenzen wissen, dann seien dir folgende Fachbücher ans Herz gelegt:

Grundkurs C: C-Programmierung verständlich erklärt

C# 6 mit Visual Studio 2015: Das umfassende Handbuch: Spracheinführung, Objektorientierung, Programmiertechniken

Programmieren lernen mit Java

[TUTORIAL] Programmiere deinen eigenen Downloadmanager mit WPF

In diesem Programmieren lernen Tutorial programmierst du deinen eigenen Downloadmanager. Er wird parallele Downloads unterstützen, die heruntergeladenen Dateien im Windowsexplorer anzeigen und auch löschen können. Am Ende kannst du deiner Phantasie freien Lauf lassen und aus der vorgegebenen Basis einen ausgereiften Downloadmanager mit beliebigen Zusatzfunktionen Programmieren.

GUI WPF Download Manager

Wenn du noch nicht weißt was Schleifen, Variablen, Switch Case Anweisungen, Stringverarbeitung, Datentypen, Arrays und Vergleichsoperatoren sind dann hole das doch bitte erst einmal nach, sonst wirst du in diesem Tutorial nicht viel verstehen.

Inhalt

Um hier den Umfang nicht zu sprengen, gehe ich in dem folgenden Tutorial nicht auf jede einzelne Zeile Code ein. Wenn Fragen dazu bestehen sollten, stelle diese doch einfach unten in den Kommentaren. Außerdem ist der Quellcode auch noch zusätzlich mit Kommentaren versehen, die du in diesem Beitrag selbst nicht findest, also einfach mal herunterladen und loslegen.

Was ist WPF?

Die Windows Presentation Foundation, nachfolgend als WPF bezeichnet, wurde im Jahre 2006 mit der Version 3.0 des .NET Frameworks veröffentlicht. Die WPF ist im Grunde eine Art Nachfolger der Windows Forms API.  Es ist also eine moderne Methode um Windows Applikationen mit graphischer Benutzeroberfläche auf Basis des .NET Frameworks zu erstellen.

WPF Eigenschaften

  • Die Benutzeroberfläche wird mit XAML (extensible application markup language), einer XML ähnelnden Sprache erstellt. Das ermöglicht eine Trennung vom Design der Benutzeroberfläche und der eigentlichen Logik des Programms
  • Die Unterstützung von Grafiken wurde verbessert und die Grafikkarte statt der CPU wird für das Berechnen von Grafiken verwendet
  • Es wird eine zweiseitige Datenbindung von Steuerelementen unterstützt. Dies ist ein besonderer Vorteil gegenüber Windows Forms, muss man dort jedes Mal mit Events arbeiten und die Controls direkt ansteuern
  • WPF Anwendungen können auch im Browser dargestellt werden
  • Durch die vektorbasierte Ausgabe funktioniert das Skalieren besser, bzw. die Grafiken werden nicht mehr verpixelt angezeigt

WPF Projekt erstellen

In Visual Studio gehst du über das Menu Datei – Neu – Projekt und wählst aus den Vorlagen, WPF Anwendung aus.

Visual Studio neues WPF Projekt anlegen

Und schon hast du ein neues Visual Studio Projekt von Typ WPF erstellt mit dem du jetzt beliebige Windows Anwendungen programmieren kannst.

Aufbau einer WPF Anwendung

Im mittleren Fenster bekommt man sogleich ein neues Fenster, mit dem Namen MainWindow.xaml, zu sehen. Der obere Teil ist der Designer der dem aus Windows Forms sehr ähnelt. Man kann auch hier mit der Toolbox arbeiten und per Drag und Drop Steuerelemente auf das Fenster ziehen und so eine Oberfläche designen.

WPF GUI Designer in Visual Studio

Der untere Teil des Fensters ist aber ein neuer Editor den es so in Windows Forms nicht gibt und zwar ein XAML Editor. Hier kann man mit einer XML ähnelnden Sprache die Oberfläche designen, ganz ohne .NET und auch ohne Designer.

WPF XAML Editor
WPF XAML Editor in Visual Studio

Die Dateitypen

In einem neuen WPF Projekt findet man, im Projektmappen-Explorer unter anderem die vier folgenden Dateitypen:

Dateityp Beschreibung
App.xaml Dies ist eine Datei die die XAML Sprache verwendet. Hier werden zwei Namespaces hinzugefügt. Außerdem wird ein Attribut mit dem Namen StartupUri dem Fenster zugewiesen, das nach Starten der Anwendung angezeigt werden soll.
App.xaml.cs Diese Datei ist eine so genannte Code Behind Datei zugehörig zur App.xaml. Der Code in dieser Datei wird ausgeführt sobald die Anwendung gestartet wird und das erste Fenster angezeigt wird.
MainWindow.xaml In dieser Datei wird der XAML Code zu dem Hauptfenster gespeichert.
MainWindow.xaml.cs Dies ist die so genannte Code Behind Datei zugehörig zum Hauptfenster. Hier wird der .NET Code geschrieben der direkt auf die Benutzerintaktion reagiert. Es kann zum Beispiel auf Button-Click oder viele andere Events reagiert werden.

Die Basis Oberfläche designen

Jetzt nachdem du weißt worum es sich bei WPF handelt geht es endlich los mit dem Download Manager. Dazu erstellst du bitte ein neues WPF Projekt und erstellst das folgende Fenster einfach mit der Toolbox und Drag und Drop, oder wenn du es hinbekommst, gerne auch direkt per XAML

Download Manager Benutzeroberfläche

Probiere es bitte selbst, damit du auch was lernst. Wenn du den Code benötigst, lade ihn einfach jetzt direkt am Ende dieses Beitrags runter.

Die eigentliche Logik

Als Erstes erstellst du bitte eine neue Klasse, das machst du in dem du mit der rechten Maustaste im Projektmappen-Explorer auf deinen Projektnamen (wahrscheinlich WpfApplication1) klickst und ein neues Element hinzufügst:

Neue Datei hinzufügen

In dieser Klasse kopierst du folgenden Code:

using System;	 	 

using System.ComponentModel;	 	 
using System.IO;	 	 
using System.Net;	 	 
using System.Threading;	 	 
using System.Windows;	 	 
using System.Windows.Controls;	 	 
using System.Windows.Media;	 	 

namespace WpfApplication1	 	 
{	 	 

 public class Download	 	 
 {	 	 

 public Button OpenButton { get; private set; }	 	 
 public Label FileName { get; private set; }	 	 
 public Button DeleteButton { get; private set; }	 	 
 public ProgressBar ProgressBar { get; private set; }	 	 
 public WebClient WebClient { get; private set; } 	 	 
 public Label LabelPercentage { get; private set; }	 	 
 {	 	 

 OpenButton = newOpenButton;	 	 
 FileName = fileName;	 	 
 DeleteButton = deleteButton;	 	 
 ProgressBar = progressBar;	 	 
 WebClient = webClient;	 	 
 LabelPercentage = labelPercentage;	 	 
 OpenButton.Click += buttonOpenFile_Click;	 	 
 WebClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged);	 	 
 WebClient.DownloadFileCompleted += new AsyncCompletedEventHandler(DownloadCompleted);	 	 

 }	 	 

 public void DownloadCompleted(object sender, AsyncCompletedEventArgs e)	 	 
 {	 	 

 if (e.Cancelled)	 	 
 {	 	 

 LabelPercentage.Content = "0%";	 	 
 RemoveDownloadFromGrid(); 	 	 
 }	 	 

 }	 	 

 public void RemoveDownloadFromGrid()	 	 
 {	 	 

 var grid = (Grid)VisualTreeHelper.GetParent(FileName);	 	 
 grid.Children.Remove(FileName);	 	 
 grid.Children.Remove(DeleteButton);	 	 
 grid.Children.Remove(ProgressBar);	 	 
 grid.Children.Remove(LabelPercentage);	 	 
 grid.Children.Remove(OpenButton);	 	 
 }	 	 

 public void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)	 	 
 {	 	 
 LabelPercentage.Content = e.ProgressPercentage + "%";	 	 
 ProgressBar.Value = e.ProgressPercentage;
	 	 
 }	 	 
 public void buttonDeleteClick(object sender, RoutedEventArgs e)	 	 
 {	 	 
 WebClient.CancelAsync(); 	 	 

 try	 	 
 {	 	 
 Thread.Sleep(200);	 	 
 File.Delete(FileName.Content.ToString());	 	 
 FileName.Content = "Download wurde durch den Benutzer gestoppt!";	 	 
 }	 	 

 catch (Exception ex)	 	 
 {	 	 
 MessageBox.Show("Fehler beim Löschen: " + ex.Message);	 	 
 } 	 	 
 }	 	 

 private void buttonOpenFile_Click(object sender, RoutedEventArgs e)	 	 
 {	 	 
 try	 	 
 {	 	 
 string argument = "/select, \"" + FileName.Content.ToString() + "\"";	 	 
 System.Diagnostics.Process.Start("explorer.exe", argument);	 	 
 }	 	 

 catch (Exception ex)	 	 
 {	 	 
 MessageBox.Show(ex.Message);	 	 
 } 	 	 
 }	 	 
 }	 	 
}	 	 

 

Dazu später mehr.

Als nächstes klickst du doppelt auf den Start Download Button und automatisch erstellt Visual Studio ein Event in der MainWindow.xaml.cs Datei. Der Code innerhalb dieser Methode wird aufgerufen sobald der Benutzer deiner Anwendung den Start Download Button drückt.

Bitte füge an den Anfang deiner MainWindow.xaml.cs die folgenden Using – Direktiven ein:

using Microsoft.Win32; 
using System; 
using System.Collections.Generic; 
using System.Diagnostics; 
using System.Linq; 
using System.Net; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Navigation;

Dies sind Verweise auf Teile des .NET Frameworks. Dadurch kann Code aus diesen Bereichen z.B. System.Net in dieser Datei verwendet werden.

Als nächstes füge nun folgenden Code in MainWindow.xaml.cs Klasse nach dem Codeabschnitt

public partial class MainWindow : Window
{

ein:

        List downloads;
        const int startHeight = 70;
        const string downloadTextBoxPlaceholder = "Enter new DownloadURL here...";
        public MainWindow()
        {
            InitializeComponent();

            textBoxDownloadPath.Text = downloadTextBoxPlaceholder;
            downloads = new List();
            ServicePointManager.DefaultConnectionLimit = 100;
        }

Der Code enthält:

  • Eine Liste in die nachher alle Downloads mit aufgenommen werden
  • Eine Konstante startHeight = 70 das ist die minimale Höhe auf der wir nachher die Position neuer Steuerelemente berechnen. Wofür neue Steuerlemente? Dir ist sicherlich aufgefallen, dass weder ein Downloadbalken noch ein Label für den Downloadfortschritt vorhanden sind. Diese werden nachträglich dynamisch erzeugt, sobald der Download beginnt.
  • Eine weitere Konstante „downloadTextBoxPlaceholde = „Enter new DownloadURL here…““ das ist der Platzhaltertext für die Textbox
  • Text = downloadTextBoxPlaceholder; hier wird der Platzhaltertext in die Textbox geschrieben
  • ServicePointManager.DefaultConnectionLimit = 100 mit dieser Option werden die im Standard auf 2 begrenzte parallele Downloads auf 100 erhöht. Das kannst du natürlich nach deinen Bedürfnissen anpassen

Als nächstes erstellst du eine neue Methode mit dem Namen „ValidateDownloadURL“. Diese dient dazu, zu überprüfen ob der Benutzer auch eine DownloadURL eingegeben hat.

        private bool ValidateDownloadURL()
        {
            string downloadPath = textBoxDownloadPath.Text;
            if (String.IsNullOrEmpty(downloadPath) || downloadPath == downloadTextBoxPlaceholder)
            {
                MessageBox.Show("Bitte erst eine gültige Download URL eingeben!");
                return false;
            }

            return true;
        }

Das ist natürlich nicht zwingend nötig um die Funktionalität zu gewährleisten, aber es kann verhindern, dass das Programm versucht den Donwnload zu starten, ohne dass eine DownloadURL eingegeben wurde.

Diese Methode rufst du jetzt aus dem Button-Click Event auf, also der Stelle im Code die angezeigt wird, wenn du doppelt auf den Start-Download Button klickst. Hierdurch wird überprüft ob in der DownloadURL Textbox text vorhanden ist und das es sich dabei nicht um den Platzhaltertext „“Enter new DownloadURL here…““ handelt. Sollte das aber doch der Fall sein beendet der return Befehl die weitere Ausführung von Code innerhalb der buttonDownload_Click Methode, der Download wird also nicht versucht auszuführen:

  
  private void buttonDownload_Click(object sender, RoutedEventArgs e)
        {
                if (!ValidateDownloadURL())
                {
                    return;
                }
        }

Der SaveFileDialog

Wenn jetzt der Downladbutton betätigt wurde, weiß das Programm noch nicht wohin der Download gespeichert und wie der Download benannt werden soll.

Hier hilft der SaveFileDialog des .NET Frameworks weiter. Hierzu erstelle am besten eine neue Methode mit der Zuständigkeit den Dateinamen zu bestimmen zum Beispiel folgendermaßen:

  
private string GetFileName()
        {
            var dialog = new SaveFileDialog();
            dialog.Filter = "ZipFiles|*.zip| WinrarFiles|*.rar|Executablefiles|*.exe|MSI Setup|*.msi| Image|*.iso" +
             "|All Files|*.*" + "|Word Documents|*.doc|Excel Worksheets|*.xls|PowerPoint Presentations|*.ppt" +
             "|Office Files|*.doc;*.xls;*.ppt";
            
            var result = dialog.ShowDialog(); 
            if (result == true)
            {
                return dialog.FileName;
            }
            else
            {
                MessageBox.Show("Download vom Benutzer abgebrochen!");
                return null;
            }
        }

Mit dem Filter kannst du die zulässigen Dateitypen bestimmen. Diese Methode rufst du aus der Start-Download Button_Click Methode auf. Du kommst dahin indem du doppelt auf den Start Download Button im Designer klickst. Der Benutzer bekommt dann mit Hilfe dieses SaveFileDialogs die Möglichkeit eine Datei auszuwählen.

Steuerelemente dynamisch zur Laufzeit erzeugen

Als nächstes erstellst du wieder eine neue Methode in der MainWindow.xaml.cs Klasse mit dem Namen CreateNewDownload. Diese Methode wird für dich unter anderem neue Steuerelemente erstellen die dann den aktuellen Download und seinen Status anzeigen:

 private Download CreateNewDownload(string fileName)
        {

            var newDownloadFileLabel = new Label { Content = fileName, HorizontalAlignment = HorizontalAlignment.Left, VerticalAlignment = VerticalAlignment.Top, Margin = new Thickness(26, startHeight * (downloads.Count + 1), 0, 0) };
            var newProgressBar = new ProgressBar { HorizontalAlignment = HorizontalAlignment.Left, Height = 17, Width = 280, VerticalAlignment = VerticalAlignment.Top, Margin = new Thickness(26, (startHeight * (downloads.Count + 1)) + 26, 0, 0) };
            var newPercentageLabel = new Label { Content = "0%", HorizontalAlignment = HorizontalAlignment.Left, VerticalAlignment = VerticalAlignment.Top, Margin = new Thickness(26, (startHeight * (downloads.Count + 1)) + 48, 0, 0) };
            var newDeleteButton = new Button { HorizontalAlignment = HorizontalAlignment.Left, VerticalAlignment = VerticalAlignment.Top, Content = "Löschen", Height = 20, Width = 52, Margin = new Thickness(380, (startHeight * (downloads.Count + 1)) + 23, 0, 0) };
            var newOpenButton = new Button { HorizontalAlignment = HorizontalAlignment.Left, VerticalAlignment = VerticalAlignment.Top, Content = "Öffnen", Height = 20, Width = 52, Margin = new Thickness(325, (startHeight * (downloads.Count + 1)) + 23, 0, 0) };
           
            newDeleteButton.Click += button_Click;
           
            grid.Children.Add(newDownloadFileLabel);
            grid.Children.Add(newProgressBar);
            grid.Children.Add(newPercentageLabel);
            grid.Children.Add(newDeleteButton);
            grid.Children.Add(newOpenButton);
           
            var client = new WebClient();
            var download = new Download(newDownloadFileLabel, newDeleteButton, newProgressBar, client, newPercentageLabel, newOpenButton);            

            return download;
        }

„new Label“ erzeugt ein neues Steuerlement vom Typ Label, also einer Beschriftung. In den geschweiften Klammern werden der Text des Labels, die Ausrichtung Horizontal und Vertikal, Größe und Position des Steuerlements definiert.

Der Bereich Margin = new Thickness(….) enthält in den Klammern auch die Variable startHeight zur Bestimmung des Abstands zum oberen Rand. Dieser Wert muss für jeden weiteren Download erhöht werden. Deshalb wird der Wert mit der Anzahl der Downloads multipliziert. So wird immer die passende Höhe ermittelt.

Das Gleiche wird danach für die ProgressBar, für die Anzeige des Downloadfortschritts, für ein weiteres Label zur Angabe des Downloadfortschritts in %, einen weitereren Button für das Löschen des Downloads und einen Button zum Öffnen des Downloadpfades, getan.

Der weitere Code ist durch die Kommentarblöcke die mit einem doppelten Slash // beginnen, erklärt die du sehen kannst wenn du meinen Sourcecode runterlädst und in Visual Studio öffnest.

Am Ende des Codeblocks wird mit:

var download = new Download(newDownloadFileLabel, newDeleteButton, newProgressBar, client, newPercentageLabel, newOpenButton);

ein neues Objekt vom Typ Download erstellt. Diesen Typ „Download“ hast du am Anfang selber in einen neuen Datei und einer neuen Klasse erstellt.

Die Download Klasse

Die Download Klasse bildet einen Download ab. Da mehrere Downloads parallel laufen können, kann es mehrere Objekte geben die diese Klasse nutzen.

Die Klasse enthält die Steuerelemente, den WebClient für den Download selbst, und Methoden die ausgeführt werden, wenn der Download beendet wurde, die Steuerelemente wieder von der Oberfläche entfernt werden, wenn der Download-Fortschritt sich verändert hat, der Löschen Button, oder der Datei öffnen Button geklickt wurde.

Um hier den Umfang nicht zu sprengen, gehe ich nicht auf jede Zeile Code ein. Wenn Fragen dazu bestehen sollten, schaue dir meine Downloadklasse in Visual Studio an, ich habe diese zusätzlich kommentiert oder stelle deine Fragen doch einfach unten in den Kommentaren.

Die Download Löschen Funktionalität

Dazu erstelle bitte folgende Methode in der MainWindow.xaml.cs:

 private Download CreateNewDownload(string fileName)
        private void button_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                var downloadToDelete = downloads.Where(x => x.DeleteButton == sender).Single();

                downloadToDelete.buttonDeleteClick(sender, e);
                var removedIndex = downloads.IndexOf(downloadToDelete);

                var downloadsToMove = downloads.Skip(removedIndex + 1).Take(downloads.Count).ToList();
                MoveControlsUp(downloadsToMove);

                downloads.Remove(downloadToDelete);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

Die Zeile

var downloadToDelete = downloads.Where(x => x.DeleteButton == sender).Single();

selektiert mit Hilfe von LINQ  den Download der zu dem aktuell gedrückten Button gehört. Auf diesem Button wird als nächstes die buttonDeleteClick Methode in der Download Klasse ausgeführt. Diese Methode wiederum beendet den Download, versucht die Datei auf dem Computer zu löschen und entfernt die zugehörigen Steuerelemente von der Benutzeroberfläche.

Die folgende Zeile schreibt den Index des zu löschenden Downloads, also die Stelle an der der Download in der Liste gespeichert wurde (z.B. 4) in eine neue Variable.

var removedIndex = downloads.IndexOf(downloadToDelete);

Die danach folgende Zeile wiederum ermittelt alle Downloads die einen größeren Index haben (also neuer sind) als der zu löschende Download.

var downloadsToMove = downloads.Skip(removedIndex + 1).Take(downloads.Count).ToList();

Dies ist erforderlich, denn die Steuerelemente dieser Downloads müssen schließlich alle nach oben verschoben werden, damit keine hässliche Lücke in der Oberfläche entsteht, nachdem der zu löschende Download von der Oberfläche entfernt wurde.

Position von Steuerelementen zur Laufzeit ändern

Die Methode MoveControlsUp erstellst du jetzt als nächstes in der Datei MainWindow.xaml.cs folgendermaßen:

  private void MoveControlsUp (List downloadsToMove)
        {
            foreach (var download in downloadsToMove)
            {
                download.FileName.Margin = new Thickness { Left = download.FileName.Margin.Left, Top = download.FileName.Margin.Top - startHeight, Bottom = 0, Right = 0 };
                download.DeleteButton.Margin = new Thickness { Left = download.DeleteButton.Margin.Left, Top = download.DeleteButton.Margin.Top - startHeight, Bottom = 0, Right = 0 };
                download.OpenButton.Margin = new Thickness { Left = download.OpenButton.Margin.Left, Top = download.OpenButton.Margin.Top - startHeight, Bottom = 0, Right = 0 };
                download.ProgressBar.Margin = new Thickness { Left = download.ProgressBar.Margin.Left, Top = download.ProgressBar.Margin.Top - startHeight, Bottom = 0, Right = 0 };
                download.LabelPercentage.Margin = new Thickness { Left = download.LabelPercentage.Margin.Left, Top = download.LabelPercentage.Margin.Top - startHeight, Bottom = 0, Right = 0 };
            }
        }

Hier passiert eigentlich nichts Besonderes, die Methode erwartet eine Liste von Downloads als Parameter. Diese Liste wird dann in der Schleife durchlaufen, um allen zugehörigen Steuerelementen eine neue Position zuzuweisen.

Datei im Windows Explorer anzeigen

Um die heruntergeladene Datei im Windows Explorer anzuzeigen und zu markieren hast du bereits folgende Methode in die Download Klasse eingefügt und dem ButtonClick-Event des Löschen Buttons zugewiesen:

          private void buttonOpenFile_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                string argument = "/select, \"" + FileName.Content.ToString() + "\"";
                System.Diagnostics.Process.Start("explorer.exe", argument);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }            
        }

Diese Methode erstellt erst ein Argument und startet dann einen Prozess, in diesem Fall den Prozess „explorer.exe“ und als Argument einen Selektierbefehl mit dem zu markierenden Dateinamen.

Downloadbutton Logik

Um den Download Button jetzt endgültig zum Leben zu rufen fehlt noch ein bisschen Code den du jetzt bitte einfügst. Klicke einfach doppelt auf den Starte Download Button und füge folgenden Code ein:

  
 private void buttonDownload_Click(object sender, RoutedEventArgs e)
        {
            Download download = null;
            try
            {
                if (!ValidateDownloadURL())
                {
                    return;
                }

                string downloadPath = textBoxDownloadPath.Text;
                string fileName = GetFileName();
                if (String.IsNullOrEmpty(fileName))
                {
                    return;
                }
                
                download = CreateNewDownload(fileName);                

                try
                {
                    //DownloadFileAsync ist der Befehl um den Download zu beginnen. Async damit während des Downloads weitergearbeitet werden kann.
                    download.WebClient.DownloadFileAsync(new Uri(downloadPath), fileName);
                    downloads.Add(download);
                }
                catch (Exception exception)
                {
                    download.buttonDeleteClick(null, null);
                    download.RemoveDownloadFromGrid();
                    MessageBox.Show(exception.Message);
                }
              
                textBoxDownloadPath.Text = downloadTextBoxPlaceholder;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

Was passiert hier?

Download download = null; Es wird ein Download Objekt erzeugt und mit null initialisiert.
if (!ValidateDownloadURL()) { return; } Die DownloadURL in der Textbox wird überprüft, wenn keine angegebene wird hier abgerbochen
string downloadPath = textBoxDownloadPath.Text; Die DownloadURL wird aus der Textbox in eine Variable geschrieben
string fileName = GetFileName(); Der Dateiname wird, mit Hilfe eine Benutzereingabe, bestimmt
if (String.IsNullOrEmpty(fileName)) { return; } Wenn kein Dateiname angegeben wurde, wird der Download nicht gestartet.
download = CreateNewDownload(fileName); Das downloadobjekt wird jetzt mit Leben gefüllt
download.WebClient.DownloadFileAsync(new Uri(downloadPath), fileName); Diese Zeile startet den eigentlich Download mit Hilfe des WebClients aus dem .NET Framework. Der Download wird asynchron gestartet, das bedeutet dass während des Download gleichzeitig anderer Code ausgeführt werden kann. Hierdurch werden parallele Downloads möglich.
downloads.Add(download); Der Download wird der Downloadliste hinzugefügt
catch (Exception exception) { download.buttonDeleteClick(null, null); download.RemoveDownloadFromGrid(); MessageBox.Show(exception.Message); } Dieser Codeblock wird nur ausgeführt wenn beim Starten des Downloads ein Fehler erzeugt wurde. In diesem Fall wird der Download gelöscht, von der Oberfläche entfernt und eine Fehlermeldung zurückgegeben.
textBoxDownloadPath.Text = downloadTextBoxPlaceholder; Der Platzhaltertext wird wieder in die DownloadURL Textbox geschrieben
catch (Exception ex) { MessageBox.Show(ex.Message); } Dieser Codeblock wird ausgeführt wenn es irgendwo in dem zugeordneten Try Block zu einem Fehlerfall kam. Dem Benutzer wird dann durch MessageBox.Show eine Meldung angezeigt.

Quellcodedownload

Lade hier kostenlos den gesamten Quellocde mit zusätzlich erklärenden Kommentaren herunter

 

Außerdem empfehle ich dir folgende weiterführende Lektüre für WPF und für .NET allgemein. Möchtest du noch jede Menge zusätzlicher Beispiele dann erwerbe eines meiner Anwendungspakete, über 40 Applikationen stehen jetzt zum Download bereit.

 

Du verstehst etwas nicht, oder hast andere Fragen und Anregungen, dann nutze doch die Kommentarfunktion und dir wird geholfen 🙂

Wie lerne ich Programmieren?

Wie lerne ich Programmieren? Wie werde ich ein erfolgreicher Programmierer? Was muss ich tun um Programmieren zu lernen? Diese Fragen werde ich in diesem Beitrag beantworten. Als erstes solltest du dich fragen was du genau erreichen möchtest, zum Beispiel:

  1. Du möchtest nur eine einfache Webseite zum Beispiel für dein Unternehmen oder auch privat erstellen
  2. Du möchtest eine komplexe Anwendung zum Beispiel eine Webseite oder APP erstellen mit verschiedensten Funktionen und/oder Usertypen
  3. Du möchtest ein Softwareentwickler werden
  4. Du möchtest ein eigenes Spiel programmieren
  5. Du brauchst es für deine Ausbildung oder Studium

Nachfolgend werde ich Tipps für jeden diese 5 Fälle geben. Denn die Vorgehensweise kann sich hier erheblich voneinander unterscheiden.

Du möchtest nur eine einfache Webseite erstellen

Wenn dies Fall ist, dann reicht vielleicht auch ein CMS (content management system) wie WordPress dafür aus. Wenn dies der einzige Grund ist aus dem du Programmieren lernen möchtest, dann solltest du lieber Tools wie zum Beispiel WordPress dafür nutzen, somit kannst du dich mehr auf den Inhalt, als mit dem Programmieren der Seite beschäftigen.

Du möchtest eine komplexe Anwendung erstellen

Wenn es wirklich nur um diese eine Webseite oder APP geht dann beauftrage doch jemand anderen dafür. Es gibt viele Seiten im Netz wo du sowas günstig in Auftrag geben kannst. Zum Beispiel upwork, fiverr, twago und viele weitere. Deine Motivation Programmieren zu lernen sollte schon etwas weiter reichen, als nur für ein einmaliges Projekt wie eine Webseite, sonst wirst du nicht bis zum Ende durchhalten und es lohnt sich der Aufwand nicht. Denn wenn du von 0 anfängst wirst du nicht innerhalb einer oder zwei Wochen zu einem Experten.

Du möchtest ein Softwareentwickler werden

Das ist ein guter Grund um Programmieren lernen zu wollen. Allerdings stellt sich dann sogleich die Frage, mit welcher Programmiersprache fange ich an? Dafür liefert die dieser Beitrag eine Antwort, so wie jede Menge Literaturtipps, nutze sie! Wenn du nun die Programmiersprache weißt, dann empfehle ich dir, der Reihe nach alle Beiträge dieses Blogs durchzuarbeiten, dir zusätzlich die Anwendungspakete zu erwerben, damit du gleich voll durchstarten kannst, und außerdem ein paar der Literaturtipps auf der rechten Seite zu kaufen und durchzuarbeiten. Außerdem empfehle ich dir ganz klar, dich bei Codecademy anzumelden um dich dort mit der Syntax deiner Sprache vertraut zu machen. Auch Seiten wie Selhtml sollten dein 2. zu Hause werden.

Du möchtest ein eigenes Spiel programmieren

Das kann ich gut verstehen, auch ich hatte das ziemlich schnell für mich als Ziel gesetzt. Doch ohne die Grundlagen geht hier erstmal gar nichts. Auch dir empfehle ich, arbeite alle Beiträge dieser Seite durch, beginne mit dem Ersten, und beschäftige dich mit den Grundlagen. Dann solltest du dir überlegen welche Technologie dein Spiel einsetzen soll. Generell würde ich dir empfehlen, sobald du in der Lage bist so gut wie jedes Konsolenprogramm zu entwickeln, dich mit der freien multiplattformunterstützenden Unity Engine auseinander zu setzen.

Du brauchst es für deine Ausbildung oder Studium

Hier kommt es jetzt wieder darauf an ob du es gerne machst, ob du es nachher auch in deinem Job brauchst und welche Programmiersprache du einsetzt. Ich empfehle dir die Literaturtipps aus diesem Beitrag.

Allgemeine Hinweise für Anfänger

Wenn du wirklich Programmieren lernen willst, dann solltest du dich auch unbedingt mit dem Thema Datenbanken und SQL auseinander setzen. Du solltest dich aber auch auf nicht zu viele Sprachen gleichzeitig konzentrieren. Wenn du HTML und C# oder SQL und C# gleichzeitig lernst ist es sicher kein Problem, da diese sich stark voneinander unterscheiden und du nicht durcheinander kommen wirst. Java und C# gleichzeitig zu lernen ist eine Sache von der ich dir aber auf jeden Fall abraten würde, da die Syntax schon sehr, sozusagen zum verwechseln ähnlich, aufgebaut ist. Um die Syntax einer Sprache zu erlernen empfehle ich dir noch zusätzlich Codecademy die Seite ist kostenlos und du bekommst sofort Aufgaben die du mit Hilfe eines Codeeditors lösen darfst.

Was muss ich tun um Programmieren zu lernen?

Vor allem solltest du nicht bei den ersten Problemen und Schwierigkeiten aufgeben. Du musst am Ball bleiben. Lerne Probleme zu lösen. Du solltest dir die Fähigkeit aneignen dich selbständig weiterzubilden und Probleme zu lösen von denen du anfangs keine Ahnung hast wie du sie lösen kannst. Du solltest dir vor allem erstmal eine Sprache raussuchen mit der du beginnst, welche ist hierbei gar nicht so wichtig. Ich empfehle dir C# oder Java, aber es kann auch irgendeine andere sein. Am Anfang ist die Lernkurve hoch, doch wenn du die erste Programmiersprache beherrschst, ist der Lernprozess für eine weitere Sprache lang nicht mehr so anspruchsvoll. Anfangs sind die Grundlagen ganz wichtig zum Beispiel Datentypen, Schleifen, Stringverarbeitung, Switch Case Anweisungen, Arrays, Vergleichsoperatoren und vor allem Praxis Praxis Praxis, zum Beispiel durch Codecademy. Aber natürlich muss man seinen Code auch immer wieder optimieren und vergleichen mit professionellem Code.

Wie werde ich ein erfolgreicher Programmierer?

  • Du solltest dich immer weiterbilden
  • Lerne von den Erfolgreichen
  • Lese dir alle Bücher durch die ich auf der rechten Seite empfehle
  • Besuche Schulungen
  • Lerne neue Technologien und Frameworks zum Beispiel Angular2
  • Lerne jedes Jahr eine neue Programmiersprache
  • Beschäftige dich zum Beispiel mit funktionaler Programmierung und schreibe funktionale Programme
  • Arbeite an open source Projekten mit
  • Tritt einer .NET User Group bei und tausche dich mit anderen Fachleuten aus
  • Abonniere oder lese regelmäßig Fachzeitschriften wie zum Beispiel die dotnetpro
  • Beschäftige dich mit Clouddevelopment zum Beispiel mit Azure
  • Entwickle ein eigenes Spiel mit der Unity Engine
  • Hab ein Überblick über aktuelle Entwurfsmuster und erwerbe das Wissen welches Muster für welchen Anwendungsfall am geeignetsten ist

 

Windows Forms

Dieser Beitrag ist ein Tutorial für die Erstellung eines simplen Taschenrechners mit Benutzeroberfläche. Wenn du meine bisherigen Beiträge durchgearbeitet hast, bist du mit den Grundlagen wie Schleifen, Variablen, Switch Case Anweisungen, Stringverarbeitung, Datentypen, Arrays und Vergleichsoperatoren bereits vertraut. Falls nicht empfehle ich dir, das erst nachzuholen, am besten mit dem ersten Beitrag, bevor du dir mit der zusätzlichen Komponente „Benuteroberfläche“ erhöhte Komplexität erzeugst. Dieses Beispiel ist mit Hilfe von Visual Studio in C# und mit Nutzung der Windows Forms Technologie erstellt worden. Natürlich kann auch eine andere Entwicklungsumgebung hierfür genutzt werden.

  1. Inhalt
  2. Windows Forms was ist das
  3. Windows Forms Projekt erstellen
  4. Aufbau einer Windows Forms Anwendung
  5. Ausführen der Anwendung
  6. Der Entwurfsmodus
  7. Die Oberfläche designen
  8. Events nutzen
  9. Logik implementieren
  10. Einsatzempfehlung
  11. Codedownload (kostenlos)

Windows Forms was ist das?

Windows Forms ist eine Art GUI (graphical user interface) Werkzeugkasten zum Erstellen von Programmen, die eine grafische Benutzeroberfläche haben, auf der Basis des .NET Frameworks. Also die klassischen Windows (Fenster) Anwendungen inklusive des gewohnten Windows-Designs.

Mit Windows Forms werden so genannte Smart Clients entwickelt. Smart Clients sind einfach zu entwickeln, upzudaten, können mit oder ohne Verbindung zum Internet genutzt werden und greifen auf lokale Ressourcen auf einer sichereren Art zu, als traditionelle Windows basierte Applikationen. Windows Forms gibt es schon lange, ein konkurrierendes neueres Framework ist WPF (Windows Presentation Foundation) dies bietet eine einfache zweiseitige Datenbindung an die Steuerelemente der Benutzeroberfläche und setzt außerdem das Entwurfsmuster MVVM (Model View Viewmodel) konsequent um. Da dieser Beitrag aber vor allem für Personen gedacht ist, die das erste Mal mit der Entwicklung von Benutzeroberflächen zu tun haben, wäre dies zu komplex, wird aber in einem zukünftigen Beitrag behandelt. Wenn du jetzt schon mehr zu WPF wissen möchtest empfehle ich dir folgendes Fachbuch, dass ich auch selbst gelesen habe: Windows Presentation Foundation 4. Einführung und Praxis

Windows Forms Projekt erstellen

Als erstes muss ein neues Projekt vom Typ Windows Forms-Anwendung angelegt werden:

Quelle: Eigene Darstellung

Dann erstellt eure Entwicklungsumgebung, in meinem Fall Visual Studio, für euch das Projekt mit verschiedenen Dateien.

Aufbau einer Windows Forms Anwendung

In Visual Studio findet ihr im Projektmappenexplorer (im Standard auf der rechten Seite von Visual Studio zu finden, ansonsten über „Ansicht“ -> „Projektmappenexplorer“ oder [STRG] + [ALT] + [L] aufrufbar) eine Form1.cs, eine Form1.Designer.cs, in meinem Fall noch eine Form1.resx und eine Program.cs Datei.

Quelle: Eigene Darstellung

 

Datei Erklärung
Form1.cs Die Form1 Klasse ist gesplittet in Designerdatei und Form1.cs. Die Form1 Datei enthält Code der ausgeführt wird, wenn der Benutzer Interaktionen mit der Benutzeroberfläche stattfinden lässt, also zum Beispiel einen Button drückt, die Maus bewegt, eine Taste auf der Tastatur drückt usw. Außerdem kann man in die vordefinierte eventgesteuerte Methode „Form1_Load“ Quellcode schreiben, der unmittelbar vor der Anzeige des Formulars, ausgeführt wird. Aus dieser Datei heraus wird bei der Erstellung der Form1 Klasse (um genau zu sein beim Aufruf des Form1 Konstrukturs), die Methode InitializeComponent() aus der „Form1.Designer.cs“ aufgerufen.
Form1.Designer.cs In der Designerdatei werden, in der Regel, die Steuerelemente (Controls) des Formulars deklariert, initialisiert, positioniert, Attribute gesetzt und formatiert.
Form1.resx Diese Datei habe ich manuell hinzugefügt, sie wird genutzt um Ressourcen geordnet abzulegen. Das können zum Beispiel Stringressourcen sein, also irgendwelche Zeichenfolgen (oft Wörter und Texte). Das macht Sinn damit man diese geordnet an einer Stelle ablegen kann und bei Änderungen, oder Hinzufügen einer neuen Sprache, nur an einer Stelle und nicht an 100 Stellen angepackt werden muss. Es können aber auch, wie in diesem Fall, Bilder oder Symbole, Audiodateien und weitere Ressourcentypen abgelegt werden.
Program.cs In dieser Klasse findest du den Haupteinstiegspunkt der Anwendung. Von hier aus wird das Formular Form1 erzeugt und ausgeführt.

Quelle: Eigene Darstellung

Ausführen der Anwendung

Wenn du [F5] drückst, oder über das Menü „Debuggen“ -> „Debugging Starten“ navigierst, kannst du deine Anwendung debuggen, also Starten mit zusätzlicher Option den Code zu untersuchen, während das Programm läuft. Bei einer neuen Anwendung sieht das Ganze noch recht unspektakulär aus, eine leeres Fenster wird angezeigt.

Quelle: Eigene Darstellung

Der Entwurfsmodus

Wenn du auf die Form1.cs Datei doppelt klickst, wird dir das Formular im Entwurfsmodus angezeigt. Hier bekommst du eine direkte Vorschau darauf, wie das Formular aussieht, außerdem stehen dir noch zusätzliche Optionen wie das Eigenschaftsfenster, eine Übersicht der zur Verfügung stehenden Events und eine Toolbox zur Verfügung. Mit der Toolbox (falls nicht bereits offen, wird diese über das Menü „Ansicht“ -> „Toolbox“ oder [STRG] + [ALT] + [X] geöffnet) können sehr einfach, mit der Maus per „Drag and Drop“, Steuerelemente auf das Formular gezogen werden. Dadurch werden neue Steuerelemente in der Form1.Designer.cs Datei erstellt, das kann man natürlich auch selber machen. Wenn ein Steuerelement den Fokus hat, können außerdem über das Eigenschaftsfenster, Eigenschaften wie zum Beispiel der Name des Steuerelements gesetzt werden.

Die Oberfläche designen

Nachdem wir nun eine leere Windows Forms Anwendung erstellt haben, muss die Oberfläche designt werden, nutze dazu entweder die Toolbox und die Entwurfsansicht, oder schreib direkt Code in die Form1.Designer.cs Klasse. Als Vorlage kannst du die folgende Abbildung, ohne Hintergrundbild, nutzen.

Quelle: Eigene Darstellung

Es sind also 3 Textboxen, 3 Label zu den Textboxen, 4 Radiobuttons, und 4 normale Buttons zu benennen und zu Erstellen.

Das kann zum Beispiel folgendermaßen in der Form1.Designer.cs Datei realisiert werden (am Ende des Beitrags findest du den gesamten Quellcode zum kostenlosen Download):

namespace WindowsFormsApplication1
{
partial class Form1
{
/// <summary>
/// Erforderliche Designervariable.
/// </summary>
private System.ComponentModel.IContainer components = null;

/// <summary>
/// Verwendete Ressourcen bereinigen.
/// </summary>
/// <param name="disposing">True, wenn verwaltete Ressourcen gelöscht werden sollen; andernfalls False.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}

#region Vom Windows Form-Designer generierter Code

/// <summary>
/// Erforderliche Methode für die Designerunterstützung.
/// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1));
this.textBox1 = new System.Windows.Forms.TextBox();
this.textBox2 = new System.Windows.Forms.TextBox();
this.label1 = new System.Windows.Forms.Label();
this.textBox_Ergebnis = new System.Windows.Forms.TextBox();
this.bt_berechnen = new System.Windows.Forms.Button();
this.bt_Wurzel = new System.Windows.Forms.Button();
this.bt_Reset = new System.Windows.Forms.Button();
this.bt_Beenden = new System.Windows.Forms.Button();
this.label4 = new System.Windows.Forms.Label();
this.Zahl2 = new System.Windows.Forms.Label();
this.radioButtonAddieren = new System.Windows.Forms.RadioButton();
this.radioButtonSubtrahieren = new System.Windows.Forms.RadioButton();
this.radioButtonMulti = new System.Windows.Forms.RadioButton();
this.radioButtonDividieren = new System.Windows.Forms.RadioButton();
this.SuspendLayout();
//
// textBox1
//
this.textBox1.Location = new System.Drawing.Point(73, 86);
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(109, 20);
this.textBox1.TabIndex = 4;

//
// textBox2
//
this.textBox2.Location = new System.Drawing.Point(233, 86);
this.textBox2.Name = "textBox2";
this.textBox2.Size = new System.Drawing.Size(110, 20);
this.textBox2.TabIndex = 5;
//
// label1
//
this.label1.AutoSize = true;
this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 17.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.label1.Location = new System.Drawing.Point(75, 56);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(72, 29);
this.label1.TabIndex = 6;
this.label1.Text = "Zahl1";
//
// textBox_Ergebnis
//
this.textBox_Ergebnis.Location = new System.Drawing.Point(77, 169);
this.textBox_Ergebnis.Name = "textBox_Ergebnis";
this.textBox_Ergebnis.Size = new System.Drawing.Size(105, 20);
this.textBox_Ergebnis.TabIndex = 8;
//
// bt_berechnen
//
this.bt_berechnen.Location = new System.Drawing.Point(583, 79);
this.bt_berechnen.Name = "bt_berechnen";
this.bt_berechnen.Size = new System.Drawing.Size(108, 31);
this.bt_berechnen.TabIndex = 10;
this.bt_berechnen.Text = "Berechnen";
this.bt_berechnen.UseVisualStyleBackColor = true;
this.bt_berechnen.Click += new System.EventHandler(this.bt_berechnen_Click);
//
// bt_Wurzel
//
this.bt_Wurzel.Location = new System.Drawing.Point(583, 144);
this.bt_Wurzel.Name = "bt_Wurzel";
this.bt_Wurzel.Size = new System.Drawing.Size(108, 31);
this.bt_Wurzel.TabIndex = 11;
this.bt_Wurzel.Text = "Wurzel aus Summe";
this.bt_Wurzel.UseVisualStyleBackColor = true;
this.bt_Wurzel.Click += new System.EventHandler(this.button2_Click);
//
// bt_Reset
//
this.bt_Reset.Location = new System.Drawing.Point(583, 215);
this.bt_Reset.Name = "bt_Reset";
this.bt_Reset.Size = new System.Drawing.Size(108, 31);
this.bt_Reset.TabIndex = 12;
this.bt_Reset.Text = "Reset";
this.bt_Reset.UseVisualStyleBackColor = true;
this.bt_Reset.Click += new System.EventHandler(this.bt_Reset_Click);
//
// bt_Beenden
//
this.bt_Beenden.Location = new System.Drawing.Point(583, 283);
this.bt_Beenden.Name = "bt_Beenden";
this.bt_Beenden.Size = new System.Drawing.Size(108, 31);
this.bt_Beenden.TabIndex = 13;
this.bt_Beenden.Text = "Beenden";
this.bt_Beenden.UseVisualStyleBackColor = true;
this.bt_Beenden.Click += new System.EventHandler(this.bt_Beenden_Click);
//
// label4
//
this.label4.AutoSize = true;
this.label4.Font = new System.Drawing.Font("Microsoft Sans Serif", 17.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.label4.Location = new System.Drawing.Point(72, 136);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(110, 29);
this.label4.TabIndex = 14;
this.label4.Text = "Ergebnis";
//
// Zahl2
//
this.Zahl2.AutoSize = true;
this.Zahl2.Font = new System.Drawing.Font("Microsoft Sans Serif", 17.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.Zahl2.Location = new System.Drawing.Point(228, 54);
this.Zahl2.Name = "Zahl2";
this.Zahl2.Size = new System.Drawing.Size(72, 29);
this.Zahl2.TabIndex = 15;
this.Zahl2.Text = "Zahl2";
//
// radioButtonAddieren
//
this.radioButtonAddieren.AutoSize = true;
this.radioButtonAddieren.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.radioButtonAddieren.Location = new System.Drawing.Point(403, 111);
this.radioButtonAddieren.Name = "radioButtonAddieren";
this.radioButtonAddieren.Size = new System.Drawing.Size(89, 20);
this.radioButtonAddieren.TabIndex = 16;
this.radioButtonAddieren.TabStop = true;
this.radioButtonAddieren.Text = "Addieren";
this.radioButtonAddieren.UseVisualStyleBackColor = true;
//
// radioButtonSubtrahieren
//
this.radioButtonSubtrahieren.AutoSize = true;
this.radioButtonSubtrahieren.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Bold);
this.radioButtonSubtrahieren.Location = new System.Drawing.Point(403, 158);
this.radioButtonSubtrahieren.Name = "radioButtonSubtrahieren";
this.radioButtonSubtrahieren.Size = new System.Drawing.Size(114, 20);
this.radioButtonSubtrahieren.TabIndex = 17;
this.radioButtonSubtrahieren.TabStop = true;
this.radioButtonSubtrahieren.Text = "Subtrahieren";
this.radioButtonSubtrahieren.UseVisualStyleBackColor = true;
//
// radioButtonMulti
//
this.radioButtonMulti.AutoSize = true;
this.radioButtonMulti.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Bold);
this.radioButtonMulti.Location = new System.Drawing.Point(403, 205);
this.radioButtonMulti.Name = "radioButtonMulti";
this.radioButtonMulti.Size = new System.Drawing.Size(117, 20);
this.radioButtonMulti.TabIndex = 18;
this.radioButtonMulti.TabStop = true;
this.radioButtonMulti.Text = "Multiplizieren";
this.radioButtonMulti.UseVisualStyleBackColor = true;
//
// radioButtonDividieren
//
this.radioButtonDividieren.AutoSize = true;
this.radioButtonDividieren.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Bold);
this.radioButtonDividieren.Location = new System.Drawing.Point(402, 256);
this.radioButtonDividieren.Name = "radioButtonDividieren";
this.radioButtonDividieren.Size = new System.Drawing.Size(97, 20);
this.radioButtonDividieren.TabIndex = 19;
this.radioButtonDividieren.TabStop = true;
this.radioButtonDividieren.Text = "Dividieren";
this.radioButtonDividieren.UseVisualStyleBackColor = true;
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.SystemColors.ControlLightLight;
this.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("$this.BackgroundImage")));
this.ClientSize = new System.Drawing.Size(730, 403);
this.Controls.Add(this.radioButtonDividieren);
this.Controls.Add(this.radioButtonMulti);
this.Controls.Add(this.radioButtonSubtrahieren);
this.Controls.Add(this.radioButtonAddieren);
this.Controls.Add(this.Zahl2);
this.Controls.Add(this.label4);
this.Controls.Add(this.bt_Beenden);
this.Controls.Add(this.bt_Reset);
this.Controls.Add(this.bt_Wurzel);
this.Controls.Add(this.bt_berechnen);
this.Controls.Add(this.textBox_Ergebnis);
this.Controls.Add(this.label1);
this.Controls.Add(this.textBox2);
this.Controls.Add(this.textBox1);
this.Name = "Form1";
this.Text = "Taschenrechner";
this.Load += new System.EventHandler(this.Form1_Load);
this.ResumeLayout(false);
this.PerformLayout();

}

#endregion
private System.Windows.Forms.TextBox textBox1;
private System.Windows.Forms.TextBox textBox2;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.TextBox textBox_Ergebnis;
private System.Windows.Forms.Button bt_berechnen;
private System.Windows.Forms.Button bt_Wurzel;
private System.Windows.Forms.Button bt_Reset;
private System.Windows.Forms.Button bt_Beenden;
private System.Windows.Forms.Label label4;
private System.Windows.Forms.Label Zahl2;
private System.Windows.Forms.RadioButton radioButtonAddieren;
private System.Windows.Forms.RadioButton radioButtonSubtrahieren;
private System.Windows.Forms.RadioButton radioButtonMulti;
private System.Windows.Forms.RadioButton radioButtonDividieren;
}
}

Jetzt haben wir die Oberfläche designt, die nötige Logik um die Funktion des Taschenrechners abzubilden fehlt aber noch.

Events nutzen

In dieser ersten, einfachen Umsetzung, wird bewusst aus Gründen der Einfachheit, auf das Konzept der Objektorientierung und andere Entwurfsmuster, verzichtet. Wenn man, in der Entwurfsansicht, auf ein Steuerelement, wie zum Beispiel den „Berechnen Button“ einen doppelten Mausklick ausführt, wird für das entsprechende „OnClick-Event“ ein Delegate erstellt, der auf die auszuführende Methode zeigt, wenn das Event ausgeführt wird (in der Datei Form1.Designer.cs).

Beispiel:

this.bt_berechnen.Click += new System.EventHandler(this.bt_berechnen_Click);
  • bt_berechnen ist ein Button, nämlich der „Berechnen Button“
  • Click ist das Event, das Eintritt wenn man mit der Maus auf dieses Element klickt
  • Diesem Event wird ein neues Objekt vom Typ „Delegate“, erzeugt durch den Aufruf EventHandler(<Name der auszuführenden Methode>), welches auf die Methode bt_berechnen_Click verweist, zugewiesen
  • Die Methode bt_berechnen_Click wird ausgeführt, wenn mit der Maus auf den Button bt_berechnen geklickt wird.

Außerdem wird die Methode „bt_berechnen_Click“ automatisch in der Form1.cs Klasse erstellt.

Diesen Vorgang kann man entweder auch automatisch, mit einem Doppelklick auf die anderen Steuerelemente nachziehen, oder besser, weil viel lehrreicher, wäre der Weg dies manuell für die anderen Steuerelemente zu realisieren.

Logik implementieren

Jetzt haben wir eine Benutzeroberfläche, wir wissen wie die Verknüpfung zwischen Buttons, Events, Delegates und der Methode auf die das Delegate zeigt, umgesetzt wird. Es fehlt also noch die eigentliche Funktion des Taschenrechners. Dazu muss in der Methode auf die das Event verweist:

  1. Der aktuelle Wert aus den Textboxen ausgelesen werden (ggf. überprüft werden, ob dieser Wert valide ist, also ob es sich um eine gültige Zahl handelt)
  2. Die Rechenoperation ausgeführt werden und somit das Ergebnis berechnet werden
  3. Das Ergebnis in die Textbox für das Ergebnis geschrieben werden

Machen wir das doch mal an dem Beispiel des „Dividieren“ Operators.

private void bt_berechnen_Click(object sender, EventArgs e)
        {
            zahl1 = Convert.ToDouble(textBox1.Text);
            zahl2 = Convert.ToDouble(textBox2.Text);

            ergebnis = BerechneGrundrechenArten();

            textBox_Ergebnis.Text = Convert.ToString(ergebnis);            
        }

Hier werden zwei zuvor Global deklarierte int-Variablen (zahl1, zahl2) die zum Datentyp double konvertierte Werte, der zugehörigen Textboxen, zugewiesen. Die Anweisung „textBox1.Text“ ruft auf der Textbox die den Namen textBox1 trägt, die Eigenschaft Text auf. Diese Eigenschaft enthält den Text der in der Textbox steht. Mit Text kann man aber nicht rechnen, deshalb muss dieser Wert erst in einen numerischen Datentyp umgewandelt, man sagt „konvertiert“, werden.

Anschließend wir eine neue Methode BerechneGrundrechenArten() ausgeführt, die wiederum das Ergebnis der Rechenoperation zurückgibt. In dieser Methode wird die Eigenschaft „Checked“ der RadioButtons, die die Rechenoperation angeben, abgefragt. Wenn „checked == true“ ist, dann ist dieser RadioButton gesetzt und es wird das Ergebnis entsprechend dieser Operation berechnet. Außerdem wird eine Division durch 0 verhindert.

 

if (zahl2 == 0 && radioButtonDividieren.Checked == true) MessageBox.Show("Division durch Null nicht zulässig", "Fehlermeldung");
            if (radioButtonAddieren.Checked == true) ergebnis += zahl1 + zahl2;
            if (radioButtonSubtrahieren.Checked == true) ergebnis -= zahl1 - zahl2;
            if (radioButtonDividieren.Checked == true) ergebnis /= zahl1 / zahl2;
            if (radioButtonMulti.Checked == true)
            {
                if (ergebnis != 0) ergebnis *= zahl1 * zahl2;
                else ergebnis = zahl1 * zahl2;
            }

            return ergebnis;

Das Ergebnis wird zurückgegeben und der ergebnis Variable aus der bt_berechnen_Click Methode zugewiesen. Anschließend wird das Ergebnis dann in den Datentyp „string“ konvertiert und der Wert wird der Eigenschaft „Text“ der Ergebnistextbox zugewiesen.

Einsatzempfehlung

Windows Forms sollte man nutzen, wenn man eine Client- oder eigenständige Windows Anwendung programmieren möchte, die auch ohne Internetverbindung zurechtkommt und außerdem die Anzahl der Formulare in einem (sehr) niedrigen Bereich angesiedelt ist. Wenn man weiß, dass man viele Formulare, benötigt oder dass die Anwendung komplexer wird, ist es empfehlenswert, sich mit WPF auseinander zu setzen, das von vornherein bidirektionale Datenbindung, so wie das MVVM Pattern unterstützt.

Download des Quellcodes

Wenn man zum erstern Mal mit Benutzeroberflächen zu tun hat, dann mag dieser Beitrag vielleicht nicht ganz trivial erscheinen. Deshalb empfehle ich den Quellcode kostenlos herunterzuladen, auszuprobieren und parallel dazu den Beitrag zu verstehen und sich selbst auszuprobieren.

Einen komplexeren, wissenschaftlichen Taschenrechner, und viele weitere lohnenswerte Applikationen kannst du im Paket User Interface erwerben.

Empfohlene weiterführende Literatur:

C# 6 mit Visual Studio 2015: Das umfassende Handbuch: Spracheinführung, Objektorientierung, Programmiertechniken

Arrays

Ein Array, manchmal als Datenfeld bezeichnet, ist eine Datenstruktur in der mehrere Variablen gleichzeitig gespeichert werden können. Die Variablen die innerhalb eines Arrays gespeichert sind, werden mit Hilfe eines Indexes aufgerufen und identifiziert.

Deklaration eines Arrays (C#, Java und weitere..)

Im Folgenden Beispiel wird ein Array deklariert:

int [] zahlen;

Durch diese Anweisung wird ein Array vom Datentyp  integer mit dem Namen „zahlen“, deklariert. Als nächstes muss das Array initialisiert werden. Dafür muss auch die Anzahl der maximal im Array abzulegenden Variablen angegeben werden:

zahlen = new int[3];

Das Array wird als neues Objekt erzeugt, daher wird das Schlüsselwort „new“ benötigt. In den eckigen Klammern steht die Anzahl der im Array enthaltenen Elemente, nämlich 3.

Alternativ kann man das Array auch in einer Zeile deklarieren und initialisieren. Dafür muss man bei der Deklaration bereits wissen, wie viele Elemente das Array genau enthalten soll:

int[] zahlen = new int[3];

Wenn bereits bei der Deklaration klar ist, welche Werte im Array gespeichert werden sollen, kann man dies auch direkt mit angeben:

int[] zahlen = new int[] {1,3,2};

Es ist sogar möglich das Ganze noch kürzer zu gestalten, folgendes Beispiel erzeugt genau das Gleiche Array wie das vorherige Beispiel:

int[] zahlen = {1,3,2};

Arrayzugriff

Durch die Initialisierung eines Arrays werden die einzelnen Elemente eines Arrays erstellt und bekommen einen Index zugewiesen. Dieser Index startet bei 0, somit ist das 1. Element eines Arrays über den Index 0 aufrufbar, das 2. Element über den Index 1 und so weiter. Das weiter oben erstellte Array hat somit drei Elemente die folgendermaßen aufrufbar sind:

zahlen[0]
zahlen[1]
zahlen[2]

Wenn nun dem zweiten Element eine Zahl zugewiesen werden soll, kann das folgendermaßen realisiert werden:

zahlen[1] = 42;

Wenn nun der Wert eines, im Array enthaltenen, Elements einer Variablen zugewiesen werden soll, geht dies einfach mit der folgenden Zuweisung:

int element2 = zahlen[1];

Mit der Eigenschaft Length kann man außerdem die Länge eines Arrays zurückgeben.

int laengeMeinesArrays = zahlen.Length;

Im Folgenden Beispiel werden zwei Arrays, deklariert, initialisiert und dann auf dem Konsolenfenster wieder ausgegeben:

            int[] zahlen = new int[3];
            string[] woerter = new string[4] { "lerne-programmieren.com ", "sind die Besten!", "von ", "Die Beispiele " };

            zahlen[0] = 3;
            zahlen[1] = 1;
            zahlen[2] = 2;
            Console.WriteLine("Arrays\n =============================================================================\n");
            Console.WriteLine("zahlen[0]= " + zahlen[0]);
            Console.WriteLine("zahlen[1]= " + zahlen[1]);
            Console.WriteLine("zahlen[2]= " + zahlen[2]);
            Console.WriteLine();
            Console.WriteLine("zahlen.Length = " + zahlen.Length);
            Console.WriteLine();
            Console.WriteLine(woerter[3] + woerter[2] + woerter[0] + woerter[1]);
            Console.ReadKey();

Konsolenausgabe:

Wenn du Hilfe benötigst, Fragen oder Anmerkungen hast kannst du hierfür die Kommentarfunktion nutzen.

Vergleichsoperatoren

Claudi Hautumm / pixelio.de

In Bedingungsanweisungen zum Beispiel bei Schleifen, oder bei einer If Anweisung, werden häufig so genannte Vergleichsoperatoren genutzt. Dafür gibt es eine entsprechende Syntax die über einige Sprachen hinweg (zum Beispiel C#, Java, C …) einheitlich ist.

Bedingung Symbol Beispiel
Kleiner als < (x < y)
Größer als > (x > y)
Kleine oder gleich <= (x <= y)
Größer oder gleich >= (x >= y)
Gleich == (x == y)
Ungleich != (x != y)

Quelle: Eigene Darstellung

Die Funktion der meisten Operatoren kann man sich denken. Jedoch enthält der „Gleich“ Operator zwei Gleichheitszeichen. Dies gibt an, dass hier eine Überprüfung auf Gleichheit stattfindet, anstatt einer Zuweisung, die ein einzelnes Gleichheitszeichen nutzen würde. In dem Beispiel x == y wird also überprüft ob die beiden Variablen, x und y gleich sind. Das Ausrufezeichen ist eine Negierung. Das Beispiel x != y prüft also ob die Variablen ungleich sind.

Außerdem kann man die Vergleichsoperatoren mit ODER und UND Verknüpfen.

Logik Symbol Beispiel
ODER || ((x < y) || (x == z))
UND && ((x < y) && (x == z))

Quelle: Eigene Darstellung

Wenn eine der beiden Bedingungen des ersten Beispiels eintrifft, also wahr ist, dann wird, durch die ODER Verknüpfung, auch die Gesamtbedingung wahr. Im zweiten Beispiel wird die Gesamtbedingung nur erfüllt, wenn sowohl die erste, als auch die zweite Bedingung, gleichzeitig erfüllt werden. Ein abstraktes Einsatzbeispiel könnte sein:

if(aktuellerHelligkeitswert < schwellenWert && lichtAus == 1)
{
//Code um Licht einzuschalten
}

Der Code um das Licht einzuschalten würde nur ausgeführt werden, wenn es aktuell dunkler ist als der definierte Schwellenwert UND das Licht auch aus ist, also die lichtAus Variable den Wert 1 enthält. Wäre nur das Licht aus oder nur der aktuelle Helligkeitswert niedriger als der Schwellenwert, würde der Code um das Licht einzuschalten, nicht ausgeführt werden.

Angenommen die lichtAus Variable wäre vom Datentyp boolean, dann könnte man die Bedingung folgendermaßen noch vereinfachen:

if(aktuellerHelligkeitswert < schwellenWert && lichtAus)
{
//Code um Licht einzuschalten
}

Der Vergleich für die Variable lichtAus wird hier selbständig anhand des Wertes durchgeführt. Wenn die Variable den Wert 1 bzw. true enthält, ist die Bedingung wahr und wenn sie 0 bzw false enthält, ist die Bedingung nicht wahr. Das kann mit einem davorstehenden Ausrufezeichen zusätzlich negiert werden.

String

Rainer Sturm / pixelio.de

Ein String stellt eine beliebige Zeichenfolge, mit einer bestimmten Enkodierung, in C# ist es UTF 16,  dar. UTF 16 (Unicode Transformation Format) unterstützt sehr viele aber nicht alle Zeichen, hier findest du eine Auflistung aller unterstützten Zeichen.  Zurück zum String, man nutzt diesen Datentyp  um Zeichenketten oder Text in einer Variable abzulegen. Dies kann zum Beispiel der Fall sein, wenn ein Benutzer Eingaben auf einem Formular zu Registrierung auf einer Webseite gemacht hat. Dann werden diese Daten meist validiert, also auf ihre Gültigkeit geprüft, mit den Daten in der Datenbank abgeglichen und bei Erfolg in der Datenbank gespeichert. In Variablen vom Typ String werden also Zeichen abgelegt die sich mit den anderen Datentypen schlecht oder gar nicht realisieren lassen. Beispielsweise könnten Kundennummern auch Buchstaben enthalten, dadurch wären diese nicht für einen numerischen Datentypen, wie integer oder double geeignet. In C# und Java bieten die Frameworks eine Vielzahl von mächtigen Funktionen in der String Klasse an. Ein paar von mir häufig genutzte Beispiele:

  • „Replace“ zum Ersetzen von Zeichen, wenn ungewünschte oder verbotene Zeichen oder Zeichenfolgen vorhanden sind.
  • Substring“ ruft einen Teil des Strings, an einer bestimmten Stelle, für eine feste Länge, auf
  • Trim“ schneidet am Ende und Anfang leere Zeichen (spaces) oder ggf. auch andere Zeichen wie führende oder anhängende 0en ab
  • Split“ unterteilt die Zeichenkette in weitere Zeichenketten zum Beispiel anhand eines Trennzeichens. Dies könnte bei CSV Dateien zum Einsatz kommen
  • Join“ ist das Gegenstück zu Split es verkettet mehrere Strings zu einem und fügt ggf. Trennzeichen ein
  • Length“ ist eine Eigenschaft und gibt die Anzahl der Zeichen dieser Zeichenkette zurück
  • Contains“ überprüft ob eine Zeichenfolge in dem String vorhanden ist
  • Equals“ überprüft ob die Zeichenfolge den gleichen Wert wie eine andere Zeichenfolge hat

Es gibt noch viel mehr Funktionen die die String Klasse mit sich bringt, die man für C# in der Microsoft, bzw. für Java in der Oracle Dokumentation alle nachschlagen kann.

Oft werden auch zwei Strings aneinander gehangen, wie im folgenden C# Beispiel:

 string vorname;
 string nachname;
 
 Console.WriteLine("\t\t\tNamenseingabe lerne-programmieren.com\n");
 Console.Write("Bitte geben Sie ihren Vornamen ein:\t");
 vorname = Console.ReadLine();
 
 Console.Write("\nBitte geben Sie Ihren Nachname ein:\t");
 nachname = Console.ReadLine();
 
 Console.WriteLine("\nSie heißen:\t\t\t\t" + vorname + " " + nachname);
 Console.ReadKey();

Der Benutzer wird gebeten, erst seinen Vornamen, danach seinen Nachnamen einzugeben. Anschließend wird sein Name auf der Konsole ausgegeben. Dazu wurde der String „Sie heißen:“ mit der Variable strVorname, einem Leerzeichen und der Variable strNachname konkateniert, also verknüpft.

Das Ergebnis sieht folgendermaßen aus:

Empfohlene weiterführende Literatur:

Grundkurs C: C-Programmierung verständlich erklärt

C# 6 mit Visual Studio 2015: Das umfassende Handbuch: Spracheinführung, Objektorientierung, Programmiertechniken

Programmieren lernen mit Java

 

Switch Case Anweisung

adel /pixelio.de

 

Die Switch Case Anweisung kann man nutzen, wenn man aus einer festen Menge von möglichen Kandidaten auswählt. Sie könnte zum Beispiel eingesetzt werden wenn auf einem Telefon eine entsprechende Taste gedrückt wurde. Wenn die 1 gedrückt wurde, könnte man zum Beispiel eine Weiterleitung an einen anderen Service implementieren. Wenn die 2 gedrückt wurde, könnte man die Weiterleitung mit einem Servicemitarbeiter umsetzen und so weiter.

Jede Switch Case Anweisung ließe sich auch mit einer „If elseif“ Anweisung umsetzen. Der Vorteil der Switch Case Anweisung ist, dass sie besser lesbar ist, da sie nicht so tief verschachtelt ist.

Der Aufbau ist recht einfach erklärt:

  1. Es startet mit dem Switch Keyword
  2. In den Klammern nach dem Keyword die Variable die überprüft wird
  3. In geschweiften Klammern, die Case Klausel gefolgt von
  4. Dem bedingten Wert und einem Doppelpunkt
  5. Dann kommt die eigentliche Anweisung die ausgeführt werden soll, wenn die Variable diesen Wert enthält.
  6. Am Ende eines Caseblocks steht das Schlüsselwort „break“. Es verhindert ein weiteres Ausführen des nachfolgenden Codes.
  7. Am Ende das optionale Schlüsselwort „default“ der hierauf folgende Code wird ausgeführt, wenn keiner der vorherigen Bedingungen wahr ist, oder bei der vorherigen Anweisung das Schlüsselwort „break“ nicht benutzt wurde.

Zum Beispiel C#, Java und weitere

Zum Beispiel C#, Java und weitere

      int number = 1;
      
      switch (number)
      {
          case 1:
              //Auszuführender Code wenn Number = 1 ist
              break;
          case 2:
              //Auszuführender Code wenn Number = 2 ist
              break;
          default:
              //Wird ausgeführt wenn andere Bedingungen nicht wahr sind
              break;
      }

VB:

Dim number As Integer = 8
 Select Case number
 Case 1
 //Auszuführender Code wenn die Number = 1 ist
 Case 2
 //Auszuführender Code wenn die Number = 2 ist
 Case Else
 //Wird ausgeführt wenn andere Bedingungen nicht wahr sind
End Select

In C# 7 wurde die Switch Anweisung weiterentwickelt. Es ist nun möglich auf jede Art von Typ ein Switch auszuführenden, zum Beispiel auf komplexe Objekte. Es können weiterführende Vergleiche (Pattern) in der Case Klausel benutzt werden. Hier findest du weiterführende Information von Microsoft. 

Um das Ganze noch ein bisschen greifbarer zu machen möchte ich gerne noch ein bisschen zusätzlichen Code mit euch teilen. Nachfolgend findet ihr Code für einen etwas erweiterten Taschenrechner, er kann auch Wurzeln ziehen und quadrieren (wenn W bzw. Q als Operator eingegeben wird). Auch Kommazahlen kann er verarbeiten, allerdings nur Zahlen zwischen -28000 und +28000. Wenn dich das stört, ändere es doch einfach ;). Wenn du Fragen hast nutze bitte die Kommentarfunktion.

using System;

namespace Rechnen
{

    class Program
    {


        static void Main(string[] args)
        {
            string strOperator;
            double dblZahl1;
            double dblZahl2;
            double dblErgebnis = 0;


            Console.WriteLine("\t\t*****\terweiterter Taschenrechner\t*****\n\n");
            Console.Write("Geben Sie die erste Zahl ein:\t\t\t\t\t");
            dblZahl1 = Convert.ToDouble(Console.ReadLine());

            if (dblZahl1 < -28000 | dblZahl1 > 28000)
            {
                Console.WriteLine("\n\nFehler: Bitte geben Sie eine Zahl zwischen -28.000 und 28.000 (achtundzwanzigtausend) ein.");
                Console.Read();
            }
            else
            {
                Console.Write("Geben Sie +, -, *, /, Q, oder W für die Rechenart ein:\t\t");
                strOperator = Console.ReadLine();

                if (strOperator == "+" || strOperator == "-" || strOperator == "*" || strOperator == "/" || strOperator == "W" || strOperator == "Q")
                {

                    switch (strOperator)
                    {
                        case "Q":

                            dblErgebnis = Math.Pow(dblZahl1, 2);
                            break;

                        case "W":

                            if (dblZahl1 < 0)
                            {
                                Console.WriteLine("\n\nFehler: Eine Wurzel aus einer negativen Zahl zu ziehen, ist leider nicht möglich, bitte geben Sie eine Zahl die <= 0 ist ein.");
                                Console.Read();
                            }
                            else
                            {
                                dblErgebnis = Math.Sqrt(dblZahl1);
                            }
                            break;

                        default:

                            Console.Write("Geben Sie die zweite Zahl ein:\t\t\t\t\t");
                            dblZahl2 = Convert.ToDouble(Console.ReadLine());

                            if (dblZahl2 < -28000 | dblZahl2 > 28000)
                            {
                                Console.WriteLine("\n\nFehler: Bitte geben Sie eine Zahl zwischen -28.000 und 28.000 (achtundzwanzigtausend) ein.");
                                Console.Read();
                            }
                            else
                            {
                                if (strOperator == "/" && dblZahl2 == 0)
                                {
                                    Console.WriteLine("------------------------------------------------------------------");
                                    Console.WriteLine("\nFehler: Eine Division durch Null ist mathematisch nicht möglich, nehmen Sie eine andere Zahl!");
                                    Console.WriteLine("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\t\t\t\t\t\t\"Development by Kai Fischer\"");
                                    Console.Read();
                                }
                                else
                                {

                                    switch (strOperator)
                                    {

                                        case "+":

                                            dblErgebnis = dblZahl1 + dblZahl2;
                                            break;

                                        case "-":

                                            dblErgebnis = dblZahl1 - dblZahl2;
                                            break;

                                        case "*":

                                            dblErgebnis = dblZahl1 * dblZahl2;
                                            break;

                                        case "/":

                                            dblErgebnis = dblZahl1 / dblZahl2;
                                            break;

                                    }
                                    if (strOperator == "+" | strOperator == "-" | strOperator == "*" | strOperator == "/" | strOperator == "W" | strOperator == "Q")
                                    {
                                        Console.WriteLine("------------------------------------------------------------------");
                                        Console.WriteLine("\nDas Ergebnis ihrer Rechnung lautet:\t\t\t\t{0}", Math.Round(dblErgebnis, 2));
                                        Console.WriteLine("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\t\t\t\t\t\t\"Development by https://lerne-programmieren.com/blog\"");
                                        Console.Read();
                                    }
                                }

                            }
                            break;

                    }
                }
                else
                {
                    Console.WriteLine("------------------------------------------------------------------");
                    Console.WriteLine("\nDies war keine gültige Eingabe für einen Operanden.\nBitte geben Sie +, -, *, /, Q oder W ein.");
                    Console.WriteLine("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\t\t\t\t\t\t\"Development by https://lerne-programmieren.com/blog\"");
                    Console.Read();
                }
            }
        }

    }
}



Empfohlene weiterführende Literatur:

Grundkurs C: C-Programmierung verständlich erklärt

C# 6 mit Visual Studio 2015: Das umfassende Handbuch: Spracheinführung, Objektorientierung, Programmiertechniken

Programmieren lernen mit Java

For Schleife

Rainer Sturm / pixelio.de

For Schleifen sind eine der grundlegenden Kontrollstrukturen, die in so gut wie jeder Programmiersprache genutzt werden. In diesem Tutorial möchte ich euch zeigen wofür man eine For Schleife verwendet, wie sie aufgebaut ist, wie sie funktioniert, und natürlich auch entsprechenden Beispielcode mit euch teilen.

Schleifen werden zum Beispiel dafür genutzt um einen bestimmten Vorgang zu wiederholen. Das könnte der Fall sein, wenn man eine Sammlung von Daten, Datensatz für Datensatz, überprüft. Es könnte auch genutzt werden um zum Beispiel Daten in einer Listenansicht, Eintrag für Eintrag hinzuzufügen, die dem Benutzer dann angezeigt werden können. Forschleifen werden vor allem dann genutzt, wenn der Zähler der Schleife benötigt wird, zum Beispiel um auf ein Listenelement mit genau diesem Index zuzugreifen.

Aufbau C# & Java:

 for (int i = 0; i < anzahlDurchläufe; i++)
 {

 }

Die Syntax für eine Forschleife ist in den meisten Sprachen (z.B. Java, C#, JavaScript) sehr ähnlich:

  1. Es beginnt mit dem reservierten Wort „for“
  2. danach folgt eine Klammer,
  3. die Deklarierung (also Benennung der Laufvariable) und
  4. Initialisierung (Zuweisung) einer Variable, in dem Fall „i“, gefolgt von einem Semikolon.
  5. Dann kommt die Abbruchbedingung, bzw. um es genauer zu formulieren, ist es eigentlich die Weiterlaufbedingung. Solange diese Bedingung erfüllt ist wird die Schleife immer wieder neu durchlaufen, bis die Bedingung nicht mehr erfüllt ist.
  6. Zuletzt wird die Operation angegeben die bei jedem Durchlauf der Schleife einmal ausgeführt wird. In diesem Fall wird die Laufvariable i immer um 1 inkrementiert, also hochgezählt.

Alternativer Aufbau in VB:

 For i As Integer = 0 To anzahlDurchläufe
 
 
 Next

Jetzt zu dem praktischen Teil. Das folgende Beispiel gibt alle ganzen Zahlen von 1 bis inklusive 9 auf der Konsole aus:

C#:

 for (int i = 1; i < 10; i ++)
      Console.WriteLine(i);

Java:

for (int i = 1; i < 10; i ++)
     System.out.println(i)

Das Ganze ist auch umgekehrt ganz einfach möglich. Dieses Beispiel gibt alle ganzen Zahlen von 10 bis inklusive 2 aus.

C#:

for (int i = 10; i > 1; i--)
     Console.WriteLine(i);

Java:

 for (int i = 10; i > 1; i--)
      System.out.println(i)

Jetzt versuch doch mal mit mehreren, auch ineinander geschachtelten, For Schleifen in einem Konsolenprogramm das Haus von Nikolaus zu zeichnen. Oder eine Pyramide die auf dem Kopf steht. Falls du keine Idee hast wie das zu realisieren ist, hier ein Beispiel von mir für eine normale Pyramide, inklusive der Benutzereingabe, wie hoch die Pyramide sein soll. Wenn du noch Fragen hast, stelle diese bitte in den Kommentaren:

using System;


namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("\t\t\t\tPyramide\n\n");
            Console.Write("Bitte geben Sie die Höhe ein:\t\t\t");
            int hoehe = Convert.ToInt32(Console.ReadLine());

            for (int i = 1; i <= hoehe; i++)
            {
                for (int j = 0; j < hoehe - i; j++)
                {
                    Console.Write(" ");
                }

                for (int k = 0; k < i * 2 - 1; k++)
                {
                    Console.Write("x");
                }
                Console.WriteLine();


            }
            Console.ReadLine();
        }
    }
}

 

Empfohlene weiterführende Literatur:

Grundkurs C: C-Programmierung verständlich erklärt

C# 6 mit Visual Studio 2015: Das umfassende Handbuch: Spracheinführung, Objektorientierung, Programmiertechniken

Programmieren lernen mit Java