Fachhochschule Westküste Hochschule für Wirtschaft & Technik Wirtschaftsinformatik .NET & C# - 2012 - C# - Programmierung - .Net Klassenbibliothek - Stand SS 2016 Prof. Dr. Burkhard Müller .NET-Framework & C#.NET Literatur zur Veranstaltung Autor Louis, Dirk Kansy, Thorsten Strasser, Shinja Titel Verlag Visual C# 2012 Entwicklerbuch Microsoft Press Visual C# 2012 Grundlagen der Programmierung Herdt-Verlag VCSPNET2012 ISBN 978-3-86645-565-8 - Seite 2 - .NET-Framework & C#.NET Gliederung A. Grundlagen & Strukturen ........................................................................ 7 1 Einführung in die .Net – Programmierung ............................................. 7 1.1 Visual Studio & .Net-Framework ......................................................... 8 1.2 Visual Studio - Starten & Beenden.................................................... 10 1.3 Ausgewählte Anwendungstypen ....................................................... 12 1.3.1 Konsolen – Anwendung ............................................................. 12 1.3.2 Windows-Anwendung ................................................................ 13 1.3.3 VSTO-Anwendung für Excel ...................................................... 16 1.4 VS-Dokumentation ............................................................................ 17 1.4.1 Zugang zur Dokumentation........................................................ 17 1.4.2 Installation lokaler Hilfeinhalte ................................................... 18 1.4.3 Dokumentationen ....................................................................... 19 1.5 Zusammenfassung ............................................................................ 20 2 Objektorientierte Programmierung – Theorie I.................................... 22 2.1 Differenzierung & Strukturen ............................................................. 22 2.2 Einstiegsbeispiel ............................................................................... 23 2.3 Strukturen der Programmiersprache C# ........................................... 26 2.3.1 Grammatik der Programmiersprache C# ................................... 26 2.3.2 Elemente der Programmiersprache C# ..................................... 27 2.4 Strukturen von Klassen ..................................................................... 29 2.4.1 Klassen & Objekte und deren Member ...................................... 30 2.4.1.1 Klassen <=> Objekte, Instanziierung ..................................... 30 2.4.1.2 Klassen-Member - Bestandteile von Klassen und Objekten .. 31 2.4.2 Klassen & Objekte in C# ............................................................ 32 2.4.2.1 Klassen der FCL ..................................................................... 33 2.4.2.2 Eigene Klassen ...................................................................... 35 3 .NET-Entwicklungsumgebung .............................................................. 37 3.1 Grundlagen des .NET-Framework .................................................... 37 3.1.1 Komponenten des .NET-Framework ......................................... 37 3.1.2 Kompilierungsphilosophie des .NET-Framework ....................... 38 3.1.3 Zusammenfassung .................................................................... 39 3.1.4 Veröffentlichung von Anwendungen .......................................... 40 3.2 Die IDE - Visual Studio .NET ............................................................ 41 3.2.1 Visual Studio und alternative Entwicklungsumgebungen .......... 41 3.2.2 Aufruf der Entwicklungsumgebung (IDE) in Visual Studio ......... 42 3.2.3 Speichern & Portieren von Projekten ......................................... 43 3.2.4 Komponenten der IDE ............................................................... 44 3.2.5 Generelle Einstellungen für die IDE ........................................... 45 3.3 C#-Programmierung in Visual Studio .NET....................................... 46 3.3.1 Anweisungen & Blöcke .............................................................. 46 3.3.2 Kommentare .............................................................................. 47 3.3.3 Konventionen für Bezeichner ..................................................... 48 3.3.4 Änderung von Bezeichnern........................................................ 49 - Seite 3 - .NET-Framework & C#.NET 3.3.5 Anatomie von C#-Anwendungen ............................................... 50 3.3.5.1 Konsolen-Anwendungen ........................................................ 51 3.3.5.2 Windows-Anwendungen......................................................... 52 3.3.6 Debug-Fenster ........................................................................... 55 3.3.6.1 Vorgehensweisen ................................................................... 55 3.3.6.2 Debug-Ansichten .................................................................... 56 3.3.6.3 Anzeigen von Variablenwerte................................................. 57 3.3.7 Projektmappen-Explorer & Symbole .......................................... 58 B. Programmiersprache Visual C# ............................................................ 60 4 Exkurs: Klassen für die Konsolen-Programmierung .......................... 60 4.1 4.2 4.3 5 Console-Klasse ................................................................................. 60 Convert-Klasse .................................................................................. 60 Formatierung von Ausgaben ............................................................. 61 Datentypen I ............................................................................................ 64 5.1 Typen - Common Type System vs. Programmiersprache ................ 65 5.2 Differenzierung der Datentypen ........................................................ 66 5.2.1 Differenzierung der Typen ......................................................... 66 5.2.2 Werttpyen ................................................................................... 67 5.3 Datentypen in C# .............................................................................. 68 5.4 Methoden von Datentypen ................................................................ 70 5.5 Literale............................................................................................... 73 5.6 Variablen und Konstanten ................................................................. 74 5.7 Operatoren und Ausdrücke ............................................................... 76 5.8 Konvertierung von Datentypen.......................................................... 79 6 C#-Anweisungen .................................................................................... 81 6.1 Vom Problem zum Programm ........................................................... 82 6.1.1 Beispiel für Vorgehensweise...................................................... 83 6.1.1.1 Problemanalyse ...................................................................... 84 6.1.1.2 Struktogramm ......................................................................... 87 6.1.1.3 Codierung ............................................................................... 88 6.1.2 Grundsätzliches zur Problemanalyse ........................................ 89 6.1.3 Kontrollstrukturen ....................................................................... 90 6.2 Kontrollstrukturen .............................................................................. 91 6.2.1 Alternationen (Verzweigungen).................................................. 91 6.2.1.1 Einseitige Auswahl ................................................................. 92 6.2.1.2 Zweiseitige Auswahl ............................................................... 95 6.2.1.3 Mehrseitige Auswahl .............................................................. 98 6.2.1.4 Mehrstufige Auswahl ............................................................ 101 6.2.2 Iterationen ................................................................................ 104 6.2.2.1 Zählergesteuerte Iteration .................................................... 105 6.2.2.2 Bedingte Iteration - kopfgesteuert ........................................ 110 6.2.2.3 Bedingte Iteration - fußgesteuert .......................................... 113 6.3 Übungen .......................................................................................... 116 6.3.1 Endwertmethode ...................................................................... 116 - Seite 4 - .NET-Framework & C#.NET 6.3.2 6.3.3 6.3.4 6.3.5 7 Degressive Abschreibung 1 ..................................................... 118 Degressive Abschreibung 2 ..................................................... 120 Prämienberechnung ................................................................. 122 Zinsrechnung ........................................................................... 125 Datentypen II - Array ............................................................................ 130 7.1 Grundsätzliches zum Array ............................................................. 131 7.2 Eindimensionales Array .................................................................. 133 7.2.1 Eindimensionales alphanumerisches Array ............................. 134 7.2.2 Eindimensionales numerisches Array ...................................... 136 7.2.3 Eindimensionales, variables numerisches Array ..................... 138 7.3 Zweidimensionales Array ................................................................ 140 7.3.1 Zweidimensionales numerisches Array ................................... 141 7.3.2 Zweidimensionales, variables numerisches Array ................... 143 7.4 Rechnen im Array ........................................................................... 145 7.4.1 Rechnen im eindimensionalen Array ....................................... 145 7.4.2 Rechnen im eindimensionalen, variablen Array ...................... 147 7.4.3 Rechnen im zweidimensionalen Array ..................................... 150 7.4.4 Rechnen im zweidimensionalen, variablen Array .................... 154 7.5 Übungen .......................................................................................... 158 7.5.1 Gewinn-Ermittlung (Array fix) ................................................... 158 7.5.2 Gewinn-Ermittlung (Array variabel) .......................................... 162 C. Klassen der FCL & Windowsanwendungen ...................................... 166 8 .NET-Entwicklungsumgebung - Teil 2 ................................................ 166 8.1 8.2 8.3 9 Ansicht der IDE ............................................................................... 167 Rückblick: Beispiel für Windows-Anwendung ................................. 169 Rückblick: Anatomie von Windows-Anwendungen ......................... 171 Objektorientierte Programmierung - Theorie Teil 2 .......................... 174 9.1 9.2 9.3 9.4 9.5 9.6 Klassen & Klassenmember ............................................................. 175 Vererbung & Instanziierung............................................................. 176 Vererbung bei Windows-Anwendungen .......................................... 177 Instanziierung bei Windows-Anwendungen .................................... 178 Klassen der FCL & Klassenmember ............................................... 179 Eigenen Klassen & Klassenmember ............................................... 181 10 Namespace System.Windows.Forms ................................................. 183 10.1 Strukturen des Namespace System.Windows.Forms ..................... 183 10.2 Überblick ......................................................................................... 186 10.3 Elementare Steuerelemente (Klassen) ........................................... 190 10.3.1 Button-Klasse ........................................................................... 191 10.3.2 Label-Klasse ............................................................................ 192 10.3.3 TextBox-Klasse ........................................................................ 193 10.4 Übungen - Elementares .................................................................. 194 10.4.1 Division zweier Zahlen ............................................................. 194 10.4.2 Rabatt-Berechnung .................................................................. 197 - Seite 5 - .NET-Framework & C#.NET 11 DataGridView-Klasse ........................................................................... 200 11.1 DataGridView-Klasse - Überblick .................................................... 200 11.1.1 Grundlegende Strukturen......................................................... 201 11.1.2 Exkurs: Collection-Klasse ........................................................ 202 11.1.3 Columns- und Rows-Eigenschaft............................................. 203 11.1.4 Aufbau eines DataGridView-Objektes ..................................... 205 11.1.5 Schematische Darstellung von Rows & Cells .......................... 207 11.1.6 Variabler Zugriff auf Rows & Cells ........................................... 208 11.2 Berechnungen - Grid <=> Array ...................................................... 209 11.2.1 Dimensionierung des Arrays .................................................... 210 11.2.2 Übertragung der Daten: Grid => Array..................................... 211 11.2.3 Berechnungen im Array ........................................................... 213 11.2.4 Übertragung der Daten: Array => Grid..................................... 214 11.3 Optische Gestaltung des DataGridView-Objekts ............................ 216 11.3.1 Objekthierarchie ....................................................................... 217 11.3.2 Gestaltung durch CellStyle-Eigenschaften .............................. 219 11.3.3 Zugriff über Name-Eigenschaft ................................................ 221 11.3.4 Gestaltung durch CellStyle-Objekte ......................................... 222 11.4 Übungen & Fragen .......................................................................... 224 11.4.1 Kapital-Verlauf (Variante 1)...................................................... 224 11.4.2 Kapital-Verlauf (Variante 2)...................................................... 226 11.4.3 Endwert-Methode (Variante 1) ................................................. 228 11.4.4 Endwert-Methode (Variante 2) ................................................. 231 11.4.5 Lotto-Gewinn ............................................................................ 233 11.4.6 Prämien-Berechung ................................................................. 236 11.4.7 Kosten- und Gewinnvergleich .................................................. 240 11.4.8 Break-Even-Analyse ................................................................ 247 11.4.9 Verteilung von Gemeinkosten .................................................. 250 - Seite 6 - .NET-Framework & C#.NET A. Grundlagen & Strukturen In diesem Kapitel werden die Grundlagen für den Umgang mit der Visual Studio Umgebung, der sogenannten IDE (Integrierte Entwicklungsumgebung / Integrated Development Environment), gelegt. Struktur der IDE Ausgewählte Anwendungstypen Klassen & Objekte 1 Einführung in die .Net – Programmierung In diesem Abschnitt wird zum einen ein Überblick über die .Net-Entwicklungsumgebung gegeben, damit jedem Studierenden die Strukturen der Umgebung und der zu erstellen Programme verständlich sind. Anhand von drei Beispielen werden die für BWL-Studierenden typischen .Net-Anwendungenstypen vorgeführt. Wichtig Nicht alles werden Sie gleich im Detail verstehen. Das kann auch nicht anders sein und macht an dieser Stelle auch nichts. Es geht erst einmal nur um einen Überblick – die Vertiefung folgt in den späteren Kapiteln. Des Weiteren werden einige Fachbegriffe in diesem ersten Kapitel den bereits programmiererfahrenen Studierenden etwas unprofessionell vorkommen. Ertragen Sie es mit Fassung, die exakten Definitionen werden zum einem späteren Zeitpunkt eingeführt. Inhalte Aufruf und Beenden der IDE Struktur und Speichern von VS-Projekten Beispiele für Anwendungstypen Konsolen-Anwendungen Windows-Anwendungen VSTO-Anwendungen für Excel Kompilieren und verteilen von VS Projekten - Seite 7 - .NET-Framework & C#.NET 1.1 Visual Studio & .Net-Framework Visual Studio-Entwicklungsumgebung - IDE Eine Entwicklungsumgebung, auch Integrated Development Environment oder kurz IDE, ist eine Toolbox, die Werkzeuge für eine komfortable Programmierung zur Verfügung stellt. Visual Studio - kurz VS - ist die Entwicklungsumgebung von Micrososft für die .Net-Programmierung Diese ist kostenpflichtig, wird aber Studierenden über die Hochschulen kostenlos zur Verfügung gestellt. .Net – Programme müssen nicht zwingend mit Visual Studio entwickelt werden; es reicht auch ein Editor wie Notepad o.ä. aus. Dieser ist dann nur nicht so komfortabel. .Net-Framework Unabhängig von der VS-IDE stellt Microsoft jedem Entwickler kostenfrei das .Net-Framework, auch Framework Class Library oder kurz FCL, zur Verfügung. Diese Klassenbibliothek (Class Library) enthält eine Vielzahl von Klassen, die für die Programmierung benötigt werden. Beispiele für Klassen sind die aus den üblichen Windows-Anwendungen bekannten Elemente wie Button, Label usw. Diese Klassenbibliothek und ein Editor sind die Minimalanforderungen für die .Net-Programmierung. Strukturen der .Net-Entwicklungsumgebung - IDE Die Elemente in der DIE sind: In der .Net-Klassenbibliothek sind die wichtigesten Klassen (Button, Label usw.) zusammengefasst. Das Common Type System stellt die Datentypen, die zum Speichern von Informationen benötigt werden, zur Verfügung. Die Programmiersprachen und der Editor sind für das Schreiben eines Programmes erforderlich. - Seite 8 - .NET-Framework & C#.NET Klassen & Objekte Der zentrale Begriff der objektorientierten Programmierung ist der der Klasse bzw. des Objekts. Eine Klasse ist die Vorlage - mache sagen auch der BluePrint - für etwas. Dieses Etwas kann z.B. ein Button oder ein Label sein. Im Grunde liegt jedem Element, das Ihnen von einer Windows-Oberfläche her bekannt ist, eine Klasse zugrunde. Die Vorlage wird als Klasse, das konkrete Element auf der Windowsoberfläche als Objekt bezeichnet. Man kann zur Veranschaulichung auch den Vergleich mit dem Objekt "Tisch" heran ziehen. Die Konstruktionszeichung eines Tisches wäre die Klasse, der konkrete Tisch wäre das Objekt. Wichtig Die Klasse enthält die Struktur, d.h. welche Platzhalter sind für diese Art von Objekten notwnedig sind, aber keine konkreten Werte Das Objekt baut auf dieser Struktur der Klasse auf enthält dann die konkreten Werte Anmerkung Der Begriff "Platzhalter" ist im Zusammenhang mit der Programmierung nicht sehr professionell - die korrekte Definition erfolgt aber später! - Seite 9 - .NET-Framework & C#.NET 1.2 Visual Studio - Starten & Beenden Einstieg in Visual Studio .Net Nachstehend finden Sie als ersten das Einstiegsfenster von VS.Net 2012. Aktivieren Sie dort über die Menü-Items -> Datei -> Projekt -> neu das nachstehende Fenster zum Erstellen eines neuen Projektes aus. - Seite 10 - .NET-Framework & C#.NET Wichtige Anmerkungen: Beim erstmaligen Aufruf von VS.Net (nach der Installation) werden Sie nach Ihrer Programmiersprachen-Umgebung gefragt. Wenn Sie dort Visual C# angegeben haben erscheint auch Visual C# in dem linken Teil des Fensters als erstes als Vorlage. Andere Sprachen z.B. Visual Basic - finden unter dem Knoten "Andere Sprachen". Sollten Siem beim ersten Aufruf z.B. versehentlich als typische Sprachumgebung Visusal Basic gewählt haben, so erscheint an erster Stelle eben Visual Basic und Sie finden C# unter dem Knoten "Andere Sprachen". In diesem Skript wird die Programmiersprache C# zugrunde gelegt. Es ist wichtig, dass auch nur Anwendungstypen unterhalb des Knotens "Visual C#" ausgewählt werden. In dem mittigen Hauptfenster ist die gewünschte Vorlage zu wählen. Hier sind vorerst nur Konsolen- oder WindowsForms- Anwendungen relevant. Die entsprechende Vorlage ist durch einmaliges Klicken zu selektieren. In dem unteren Teil des Fensters ist der Name des Projektes und der Speichort anzugeben. Der Name des Projekts ist dann auch der Name des Pfades, unter dem alle Projektdateien gespeichert werden. Vermeiden Sie bei dem Bezeichner Sonderzeichen und Leerschritte. - Seite 11 - .NET-Framework & C#.NET 1.3 Ausgewählte Anwendungstypen 1.3.1 Konsolen – Anwendung IDE für Konsolen-Anwendungen Beim Start der IDE für die Entwicklung einer Konsolen-Anwendungen wird das nachstehende Fenster mit dem vorbereiteten Code geöffnet. Struktur einer Konsolen-Anwednung Using-Anweisungen für die Einbindung der Namespaces Namespace Klasse Methode (allgemein Member der Klasse) Code Erstellung Dieser Code ist um die unten markierten Zeilen zu ergänzen. Programm-Code Programm - Ausführung (Laufzeit) Funktions-Taste <F5> oder über das Menü „-> Debuggen -> Debugging starten“ Zur Laufzeit wird dann der Text „Hello World“ auf den Bildschirm ausgegeben. Durch die <Enter>-Taste wird zur IDE zurückgekehrt. - Seite 12 - .NET-Framework & C#.NET 1.3.2 Windows-Anwendung IDE – für Windows-Anwendungen Bei der Entwicklung von Windows-Anwendungen ist die Entwicklung in zwei Komponenten zu differenzieren: Programmierung in der bekannten Code-Ansicht Gestaltung der Oberfläche (GUI – Graphic User Interface), d.h. des Formulars oder der Form, in der Designer-Ansicht. Klassen für die GUI-Gestaltung (Controls) Projekt-Explorer Form Member (Eigenschaften) des aktiven Objektes - Seite 13 - .NET-Framework & C#.NET Erstellung der Form (Designer der IDE) Instanziierung einer Klasse Ziehen einer Klasse (Vorlage) aus der ToolBar auf die Form Anmerkung ToolBar -> Klasse Formular -> Objekt oder Instanz Optische Veränderung des Objekts Anklicken des Objektes (Objekt selektieren) „Anfasser“ am Rand des Objektes sind aktiv Größenveränderung durch Ziehen der Anfasser Verschiebung mit gedrückte linker Maus-Taste verschieben Eigenschaften (Member) von Klassen / Objekten Ist ein Objekt selektiert (Anfasser des Objektes sind sichtbar), können auch über das Eigenschaften-Fenster die Werte der Eigenschaften des Objektes geändert werden. Zentrale Eigenschaften Size-Eigenschaft für Größe des Objektes Location-Eigenschaft für die Position - ausgehend von der linken oberen Ecke der Form – des Objektes. Text-Eigenschaft für die Beschriftung des Objektes Die endgültige Form könnte z.B. das folgende Layout besitzen. Anmerkung Allerdings geht auch die Arbeit mit Designer nicht ohne Code. Zu einer mit dem Designer entworfene Form wird von der IDE automatisch der Code erzeugt, der die Objekte zur Laufzeit anzeigt. Wo dieser Code abgelegt wird, wird später erläutert. - Seite 14 - .NET-Framework & C#.NET Erstellung des Codes – Ereignisorientierte Methoden Im Gegensatz zu Konsolen-Anwendung werden Windows-Anwendung über Objekte und deren Ereignisse (Events) gesteuert (Beispiel: Objekt Button und Click-Event). Dieses bedeutet, dass das Programm erst ausgeführt wird, wenn bei einem Objekt ein bestimmtes Event ausgelöst wird. In den Code für ein ereignisorientiertes Programm – besser eine ereignisorientierte Methode – gelangt man durch das doppelte Klicken auf das gewünschte Objekte im Designer. Will man folglich zu dem obigen Button „btnStart“ eine Methode erstellen, so gelangt man durch den Doppelklick in den nachstehenden bereits generierten Code. Automatisch generierter Code Die Methode, die beim Klicken des Button „btnStart“ und „btnEnde“ (mit der Beschriftung „Ausgabe“) ausgeführt wird, ist nachstehend abgebildet. Laufzeit Nach dem Klicken (Click-Event) auf den Button „btnStart“ erscheint in dem Label „lblAusgabe“ der Text „Hello World“. Der Text wird folglich dadurch angezeigt, dass der Text-Eigenschaft des Labels - Seite 15 - .NET-Framework & C#.NET 1.3.3 VSTO-Anwendung für Excel IDE für Excel-Anwendung Bei VSTO-Applikationen (Visual Studio Tools for Office) wird an Stelle der Form das Objekt der entsprechenden Office-Anwendung als Vorlage verwendet. Bei dem nachstehenden Beispiel dient daher ein Excel-Sheet als Vorlage. Code Form - Seite 16 - .NET-Framework & C#.NET 1.4 VS-Dokumentation 1.4.1 Zugang zur Dokumentation Die VS-Dokumentation verfügt über eine Suchfunktion durch eine Freitextsuche oder durch vorgeschlagene Knotenpunkte sowie innerhalb des Codes auch über eine kontextsensitive Hilfe. Je nach Fragestellung sind unterschiedliche Zugägne zur Dokumentation sinnvoll. F1-Taste Befehl oder Objekt makrieren und drücken der F1-Taste, so öffnet sich die Hilfe zu genau diesem Befehl. Struktur-Knotenpunkte Wissen Sie nicht, welchen Befehl Sie gerade benötigen, ist es sinnvoll, entweder die Freitext-Suche zu nutzen oder über die Knotenpunkte in der Doku zu suchen. Dies wird weiter unten noch erläutert. Hilfe-Einstellungen Quelle festlegen Zuerst ist wichtig, wie die Hilfetexte dargestellt und von wo diese Texte geladen werden sollen. Über "Hilfe" -> "Hilfeeinstellung festlegen" gelangt man zu den entsprechenden Optionen. Die Hilfe kann entweder im Browser oder in einem Help Viewer angezeigt werden. Hilfeinhalte hinzufügen und entfernen Das Laden der Hilfe Inhalte erfolgt über "Hilfeinhalten hinzufügen und entfernen". Der Prozeß zur Verwaltung der Hilfe-Downloads wird in einem gesonderten Fenster beschrieben. - Seite 17 - .NET-Framework & C#.NET 1.4.2 Installation lokaler Hilfeinhalte In diesem Abschnitt wird die lokale Installation des Hilfetextes beschrieben. Das nachstehende Fenster zeigt die typische Ansicht dieser Installationsumgebung. Im linken Teil des Fensters werden die bereits installierten Hilfen angezeigt. Im mittleren Teil werden alle verfügbaren Inhalte verwaltet, d.h. deren Status angezeigt. Die Aktion steht auf Entferner für bereits installietre Hilfen, dike wieder gelöscht werden sollern. Abbrechen für selektierte Hilfen, dier wieder deselektiert werden sollen. Hinzufügen für Hilfen, die noch selektiert werden können. Im rechten Teil des Fensters werden die Hilfen angezeigt, die selektiert und installiert werden sollen. Die endgültige Installation erfolgt erst, wenn Button "Aktualisieren" geklickt wurde. - Seite 18 - .NET-Framework & C#.NET 1.4.3 Dokumentationen Innerhalb der Dokumentation gibt es zwei wichtige Handbücher. Zunächst gibt es das Visual C# Programmier-Handbuch, dsas sämtliche Befehle der Sprache C# beschreibt. Weiterhin gibt es das Handbuch zur die .NET-Klassenbibliothek, welches die Klassen bzw. Objekte der Bibliothek beschreibt. Dokumentation zur Programmiersprache Visual C# Unter dem Knoten C#-Referenz ist das Handbuch für die Programmiersprache C# zu finden. Dort werden die Details zur Programmiersprache erläutert. Dokumentation zur .NET-Klassenbibliothek Unter dem Knoten .NET Framework-Klassenbibliothek ist die Beschreibung aller .NET Klassen zu finden, die aus Gründen der Übersichtlichkeit in sogenannten Namespaces organisiert sind. - Seite 19 - .NET-Framework & C#.NET 1.5 Zusammenfassung Strukturen des .Net-Frameworks IDE - Integrated Development Environment: Visual Studio (kostenpflichtig) Basisklassen-Bibliothek; FCL (Framework Class Library)/ BCL (Base Class Library) Aufruf & Beenden von VS.Net Struktur der IDE Code-Ansicht <=> Designer-Ansicht Eigenschaftenfenster Toolbar; Toolbar Anwendungstypen Konsolen-Anwendungen Windows-Anwendungen VSTO-Anwendungen (Visual Studio Tools for Office) usw. Aufbau von Konsolen-Anwendungen using-Anweisungen für einzubindende Namespaces Struktur: Namespace -> Klasse -> Main-Methode Aufbau von Windows-Anwendungen using-Anweisungen für einzubindende Namespaces Strukur: Namespace -> Klasse Form -> Konstrukutor; Ereignisbasierte Methoden - Seite 20 - .NET-Framework & C#.NET C#-Syntax-Regeln Kommentierung im Code Semikolon als Anweisungsende Klassen & Objekte Differenzierung Klassen <=> Objekte Member-Arten Eigenschaften Methoden Ereignisse Konstruktor Ansprechen von Objekten & Membern im Code Wichtige Klassen Console Button Label Methoden vordefinierte Methoden this.Close(); Console.WriteLine(); selbstdefinierte Methoden; ereignisbasierte Methoden Erzeugng durch Doppelklick im Desinger Bezeichner: Bezeichner des Objekts & Event Änderung von Eigenschaften Änderungen im Designer Änderung im Code durch Zuweisungs-Anweisung Umgang mit der Online-Dokumentation Zugang zur C#-Hilfe und deren Aufbau Zugang zur .Net-FCL-Hilfe und deren Aufbau - Seite 21 - .NET-Framework & C#.NET 2 Objektorientierte Programmierung – Theorie I Dieses Kapitel befasst sich noch einmal vertiefend mit den Strukturen der Objektorientierten Programmierung (kurz: OOP). Da der Begriff OOP bereits aus den beiden Bestandteilen objektorientiert und Programmierung besteht, folgt dieses Kapitel auch dieser Differenzierung. 2.1 Differenzierung & Strukturen Der zentrale Begriff der modernen Programmierung ist der der Objektorientierten Programmierung. Mit den Begriffen „Objektorientierung“ und „Programmierung“ sind die zwei Säulen, auf denen auch dieses Skript basiert, benannt. Die Differenzierung in Klassen und Programmierung könnte auch als falsch angesehen werden. Der Grund liegt darin, dass die Klassen – wie z.B. die Button-Klasse - natürlich mit Hilfe einer Programmiersprache entwickelt worden sind, die Programmierung daher immanent ist. Struktur des Manuskripts B. Programmiersprache Visual C# Im zweiten Teil des Skripts befassen wir uns nun genauer mit der Sprache C# und lernen dabei beispielsweise das Grid (Tabelle) und das Array (Rechenbereich einer Tabelle) kennen. In der Sprache gilt es, wie oben erläutert, sprachspezifische Ausdrücke und Zuweisungen kennenzulernen. Diese Sprachspezifikationen gelten in sämtlichen C#-Anwendungen. C. Klassen der .NET Framework Class Library & Windowsanwendungen Im dritten Teil des Skripts befassen wir uns nun mit der o.g. .NET-Umgebung. Mithilfe der Sprache C# wird innerhalb des .NET-Frameworks kommuniziert. Das .NET-Framework selbst beinhaltet Klassen, die bei der Programmierung helfen. Sie beinhalten immer Methoden(), Ereignisse und Eigenschaften. So beinhaltet beispielsweise die Klasse Convert die Methode .ToDouble(), somit kann ein Wert eingelesen werden und in eine Zahl konvertiert werden. Dies ist zunächst einmal sprachunabhängig. Die .NET-Klassenbibliothek, die nur in der .NET-Umgebung vorhanden ist, beinhaltet also nützliche, bereits "vorbereitete" Befehle. Es ist daher sinnvoll, die Klassen und somit auch die Methoden(), Eigenschaften und Ereignisse des .NETFrameworks zu nutzen. - Seite 22 - .NET-Framework & C#.NET 2.2 Einstiegsbeispiel Zu Beginn dieses Abschnittes steht wieder eine kleine Konsolen-Anwendung, an der die zentralen Erläuterungen zur Programmiersprache und zur Klassenbibliothek erfolgen werden. Bei diesem Beispiel sollen zwei Zahlen eingegeben und das Produkt dieser beiden Zahlen ausgegeben werden. Der nachstehende Screenshot zeigt den Ablauf. Code //Deklarationen double faktor1, faktor2, produkt; //Prozedur Console.Title = "Einstiegsbeispiel"; Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine("Multiplikation zweier Zahlen"); Console.WriteLine(); //Eingabe Console.Write("1. Faktor : "); faktor1 = Convert.ToDouble(Console.ReadLine()); Console.Write("2. Faktor : "); faktor2 = Convert.ToDouble(Console.ReadLine()); //Berechnung produkt = faktor1 * faktor2; //Ausgabe Console.WriteLine(); Console.WriteLine("Produkt : {0,10:N}", produkt); Console.ReadLine(); - Seite 23 - .NET-Framework & C#.NET Deklaration von Variablen Variablen dienen der temporären Speicherung von Werten. Variablen Eine Variable ist ein Speicherplatz im Hauptspeicher des Rechners Beim Ausschalten des Rechners bzw. beim Beenden des Programms wird diese wowieder gelöscht Innerhalb einer Programmiersprache wird eine Variable mit einem Bezeichner benannt, was die Verwendung deutlich vereinfacht,da man nicht mit numerischen Adresse sondern mit Namen arbeiten kann. Bezeichnung einer Variablen Die Bezeichnung einer ist grundsätzlich beliebig, unterliegt aber bestimmten Konventionen. Verwendung selbstsprechender Bezeichner. Lokale Variablen beginnen mit einem kleinen Buchstaben Sonderzeichen und Leerzeichen sind nicht zulässig. Typ Mit dem Typ wird festgelegt, was in der Variablen gespeichert werden kann. So ist beispielsweise der Type double dafür geeignet reelle Zahlen aufzunehmen; Buchstaben sind in diesem Typ nicht speicherbar. Deklaration Die Deklaration einer Variablen erfolgt durch die folgenden Anweisung erfolgen: double faktor1; double faktor1, faktor2, produkt; Speichern und Lesen von Werten Eine Wertzuweisung erfolgt durch das Gleichheitszeichen = . faktor1 = Convert.ToDouble(Console.ReadLine()); produkt = faktor1 * faktor2; Mathematische Gleichheit vs. Zuweisung Die Zuweisung ist keine mathematische Gleichheit. D.h. die Ausdrücke der Seiten dürfen nicht vertauscht werden. Es gilt immer: linke Seite = rechte Seite Ziel = Quelle Folgt in der Mathematik aus A=B auch B=A, so gilt dieses in der Informatik nicht. - Seite 24 - .NET-Framework & C#.NET Typ-Gleichheit Grundsätzlich muss auf beiden Seiten der Zuweisung der gleiche Datentyp stehen. Die folgende Anweisung ist fehlerhaft, da aus dem Tastaturpuffer auch Zeichenketten übergeben werden können und diese nicht vom Typ double sind. faktor1 = Console.ReadLine(); Diese Anweisung ist korrekt, da die Ausdrücke auf beiden Seiten der Zuweisung vom Typ double sind. produkt = faktor1 * faktor2; Konvertierung Um die Gleichheit bei einer Zuweisungs-Anweisung herzustellen existieren Konvertierungsmethoden. Ein Beispiel sind die Methoden der ConvertKlasse, mit der imnachstehenden Beispiel die Informationen des Tastaturpuffers in den Typ double konvertiert werden. Das führt aber zu einem Fehler, wenn die Informationen z.B. alphanumerisch sind. faktor1 = Convert.ToDouble(Console.ReadLine()); - Seite 25 - .NET-Framework & C#.NET 2.3 Strukturen der Programmiersprache C# Im den nachstehenden Kapiteln wird die Struktur der Programmiersprache C# erläutert. Es ist noch einmal darauf hinzuweisen, dass dieses von der Beschreibung der Klassenbibliothek, die die Klassen bzw. Objekte beinhaltet, zu unterscheiden ist. 2.3.1 Grammatik der Programmiersprache C# Grammatik einer Programmiersprache „In dieser Beschreibung wird die Syntax der C#-Programmiersprache unter Verwendung zweier Grammatiken dargestellt. Die lexikalische Grammatik definiert, wie mittels Unicode-Zeichen Zeilenabschlusszeichen, Leerraum, Kommentare, Token und Präprozessordirektiven gebildet werden. Die syntaktische Grammatik definiert, wie aus den aus der lexikalischen Grammatik resultierenden Token C#-Programme gebildet werden.“ Lexikalische Grammatik Lexikographie Erstellung von Wörterbüchern (Sprachwissenschaften). Analog einer „normalen“ Sprache werden in der lexikalischen Grammatik einer Programmiersprache die Grundlagen der Sprache definiert, wie z.B. Zeichenvorrat (welche Zeichen dürfen verwendet werden) Schlüsselworte (welche Wort dürfen gebildet werden) Kommentare (Verwendung von Kommentaren) Operatoren (zur Verknüfung) … Syntaktische Grammatik Syntax Satzlehre (Sprachwissenschaften), Regeln des Satzaufbaus, z.B. der Struktur von Haupt- und Nebensätzen usw. Analog gilt bei Programmiersprache, dass durch die syntaktische Grammatik die Regeln für die Formulierung von Ausdrücke Aufbau von Anweisungen (Schleifen, Fallunterscheidungen, …) Struktur von Namespaces, Klassen und anderer Typen … festgelegt werden. Prüfung der Grammatik durch den Compiler Die grammatikalische Prüfung erfolgt durch den C#-Compiler: Prüfung während der Codierung innerhalb der IDE Prüfung durch den Compiler vor der Übersetzung - Seite 26 - .NET-Framework & C#.NET 2.3.2 Elemente der Programmiersprache C# Bei einer Programmiersprache werden die definierten Worte als Schlüsselwörter bezeichnet. Sie sind zu unterscheiden von frei wählbaren "Worten", wie z.B. den Bezeichner von von Variablen. Die Schlüsselworte sind reserviert, d.h. es darf zum Beispiel keine Variable so bezeichnet werden wie ein Schlüsselwort. Im Editor werden Schlüsselwort dunkelblau dargestellt und sind so gut erkennbar. Differenzierung der Schlüsselwörter Im Folgenden geht es darum, die Vielzahl der Schlüsselwörter aus Gründen der Übersichtlichkeit zu differenzieren. Auf einer ersten Stufe lassen sich die folgenden zwei Gruppen bilden: Schlüsselwort, die im Zusammenhang mit den Datentypen Verwendung finden. Das ist zum Beispiel double bei der Deklaration einer Variablen. Schlüsselwort der zweiten Gruppe stehen hingegen im Zusammenhang mit Anweisungen, zum Besisiel einer Fallunterscheidung oder einer Schleife. Innerhalb dieser Gruppen lassen sich die Schlüsselworte dann weitere differenzieren, was die weiter unten stehende Grafik veranschaulicht. - Seite 27 - .NET-Framework & C#.NET Struktur des Vorlesungsmaterials Bezug zum Beispiel - Seite 28 - .NET-Framework & C#.NET 2.4 Strukturen von Klassen Verwendung von Klassen Bei allen hellblau dargestellten Elementen (Convert- und Console-Klasse) handelt es sich um Klassen. Mitglieder / Member von Klassen Member können sein Eigenschaften (Merkmale) Methoden (Fähigkeiten) Ereignisse Konstruktor Verwendung von Eigneschaften und Methoden Setzt man nach dem Klassen-Bezeichner einen Punkt so lässt sich dann aus der eingeblendeten Auswahlliste die gewünschte Eigenschaft oder Methode auswählen. Selektiert man das gewünschte Member durch Klicken, wird rechts neben der Liste ein kurzer Hilfetext eingeblendet. - Seite 29 - .NET-Framework & C#.NET 2.4.1 Klassen & Objekte und deren Member Objekte sind die zentralen Elemente moderner Programmierphilosophien. Objektorientierte Programmierung kurz OO. Objekte Alles ist ein Objekt ("Everything ist an object") Beispiele Button „Ende“, Hund „Kalle“ Schreibtisch. 2.4.1.1Klassen <=> Objekte, Instanziierung Klasse Objekt Klasse Vorlage, Blue Print Objekt konkretes Element Beispiele Konstruktuonszeichnung Schreibtisch Gene Hund Button (Toolbar) Ende-Button (Form) Instanziierung Grundsatz Eine Klasse muss erst instanziiert werden, damit die Eigenschaften und Methoden der Klasse genutzt werden können! Ausnahme (statische Member) Aber es gibt leider Ausnahmen, die dieses Prinzip durchbrechen: manchmal beißen die genetischen Grundlage eben doch ! Das ist zwar nicht in der realen Welt denkbar, jedoch in der Informatik und hier hinken dann die Vergleiche doch etwas. - Seite 30 - .NET-Framework & C#.NET 2.4.1.2Klassen-Member - Bestandteile von Klassen und Objekten Jedes Klasse bzw. jedes Objekt - wie eine Button oder ein Lebewesen – besitzt verschiedene Arten von vorgegebenen Informationen, die nachstehend kategorisiert und erläutert werden sollen. Eigenschaften (Properties) Eigenschaften: statischer Charakter, beschreiben ein Objekt Ereignisse (Events) Ereignisse: z.B. das Klicken auf ein Objekt => löst i.d.R. eine Methdoe aus Methoden Methoden machen die eigentliche Leistungsfähigkeit von Objekten aus. So existieren bspw. bei der Klasse „Console“ die Methode „WriteLine“, die die Ausgabe von Texten auf dem Bildschirm ermöglicht. Vordefinierte Methoden Biese bereits vordefinierten Abläufe bezeichnet man im Zusammenhang mit der OOP als vordefinierte Methoden. So gibt es bei der Klasse „Console“ mit „ReadLine“ und „WriteLine“ Methoden, die bereits bei der Klasse fest implementiert - also vordefiniert - sind. Selbstdefinierte Methoden Da vordefinierte Methoden häufig nicht ausreichend sind, können zusätzlich neue Methoden implementiert werden. Der Entwickler schreibt kleine Programme - Methoden -, die beim Auftreten von Ereignissen bei einem Objekt ausgeführt werden. Klickt der Anwender auf den Button zum Ausgabe, gibt das Programm den text "Hello World" auf einem Label aus. Zugegeben: das ist nicht sehr anspruchsvoll; es ist aber eine erste selbstdefinierte Methode. Überladene Methoden Methoden, die den gleichen Namen besitzen aber unterschiedliche Eingaben erfordern, bezeichnet man als überladene Methoden. So existieren z.B. bei der Methode „WriteLine“ 18 Überladungen, die sich nach dem was gerade ausgegeben werden soll - Zahl, Buchstaben usw - unterscheiden. Statische Methoden; Instanz-Methoden Will man mit einer Klasse arbeiteten, muss sie wie eingangs erläutert, erst instanziiert werden. Die statischen Methoden bilden dabei eine Ausnahme. Bestimmte Methoden, die direkt von der Klasse aus aufgerufen werden können - für die nicht erst eine Instanz (ein konkretes Objekt) notwendig ist, werden als statische Methoden bezeichnet. Konstruktor-Methode Bei der Instanziierung kommt eine besondere Methode zum Einsatz, die zwar bei Lichte betrachtet auch nur eine Methode ist, aber mit der Bezeichnung Konstruktor in besondere Weise hervorgehoben wird. Der Konstruktor ist somit nur bei der Instanziierung der Klasse von Relevanz ist. - Seite 31 - .NET-Framework & C#.NET 2.4.2 Klassen & Objekte in C# Das Thema Klassen kann aus zwei Perspektiven betrachtet werden. Verwendung der Klassen der FCL Erstellung eigener Klassen Hierarchie - Seite 32 - .NET-Framework & C#.NET 2.4.2.1Klassen der FCL Die auf der vorherigen Seite dargestellt Hierarchie soll jetzt noch einmal an der Dokumentation der Klassenbibliothek veranschaulicht werden. Namespaces der FCL Namespace System - Seite 33 - .NET-Framework & C#.NET Beispiel: Klasse Console Öffnet man als nächsten den Knoten für die Klasse Console (und selektiert die Klasse durch Klickt), so werden im linken Teil der Dokumentation die bekannten Membergruppen und im rechten Teil die Member im Detail angezeigt. Vordefinierte Methoden Grundsätzlich handelt es sich bei den Klassen der FCL immer um vordefinierte Methoden. Statische Methoden In der Methodenliste steht in der ersten Spalte bei allen Methoden ein rotes "S", was für statische Methoden steht. Überladene Methoden Konstruktor-Methode Eine Konstruktot-Methoide existiert bei Console-Klasse nicht. - Seite 34 - .NET-Framework & C#.NET 2.4.2.2Eigene Klassen Auch wenn vorerst die Entwicklung eigener Klassen nicht im Vordergrund steht, ist ein Grundverständnis für die Programmierung notwendig. Sturktur einer Konsolen-Anwendungen Gut nachvollziehbar auch hier, dass den Using-Anweisungen (werden weiter unten besporchen) mit Namespace, Klasse und Main-Methode eine identische Strukutr zu finden ist. In diesem Fall sehr simple, da innerhalb des Namespaces mit der Klasse Program nur eine Klasse und innerhalb dieser Klasse mit der Main-Methode nur eine Methode existiert. - Seite 35 - .NET-Framework & C#.NET Einbindung von Namespace-Bibliotheken Die Using-Anweisungen dienen der Einbindung von Klassen eines Namespaces. Hierdurch kann die Programmierung vereinfacht werden. Bisher wurde die Writeline()-Methode wie folgt verwendet: Console.WriteLine("Multiplikation zweier Zahlen"); Die Klasse Console ist Mitglied des Namespaces System. Würde man die entsprechende Using-Anweisung ganz oben im Code deaktivieren, könnte auf die Klasse Console nicht mehr zugegriffen werden, da dieser Namespace diesem Projekt nicht mehr bekannt ist. Die obige Fehlermeldung könnte nur durch einen sogenannten qualifizierten Zugriff – d.h. unter Angabe des Namespaces – vermieden werden. Durch die Einbinung von Namespaces mittels der Using-Anweisung läßt sich folglich der Code etwas vereinfachen. - Seite 36 - .NET-Framework & C#.NET 3 .NET-Entwicklungsumgebung 3.1 Grundlagen des .NET-Framework Die .NET-Welt besteht - wie bereits mehrfach erläutert -aus den beiden Komponenten: NET-Framework (Rahmenstruktur, welche Klassen usw. bereitstellt) Entwicklungsumgebung Visual Studio (hier programmieren wir) 3.1.1 Komponenten des .NET-Framework Struktur des .NET-Frameworks 1. Komponente Klassenbibliothek - kurz FCL. 2. Komponente Common Type System - kurz CTS. Unter .Net ist das Typ-System für alle Propgrammiersprachen identisch. Da Typen früher nur in der Programmiersprache implemnetiert waren und unter .Net in der FCL zu finden sind, gbit es unter .Net die Besonderheit, dass Typen sowohl über das entsprechende Schlüssenwort als auch über die "Klasse" der FCL deklariert werden können. 3. Komponente Common Languge Specifikation - kurz CLS - Seite 37 - .NET-Framework & C#.NET 3.1.2 Kompilierungsphilosophie des .NET-Framework Die Bezeichnung des Microsoft Entwicklungswerkzeuges als .Net Entwicklungsumgebung leitet sich aus der Philosophie zur Verteilung von Anwendungen, die heute üblicher Weise über des Netz erfolgt, ab. Jeder Quell-Code ist erst lauffähig, wenn er in die Maschinensprache des ZielRechners, auf dem das Programm laufen soll, kompiliert worden ist. Da man aber bei verteilten Anwendungen die technischen Voraussetzungen der Zielrechner häufig nicht kennt, ist diese Anforderung sehr hinderlich. Unter .Net wird daieses Problem durch eine zweistufige Kompilierung gelöst. Die erste Stufe wird IL-Code, IL für Intermediate Language - also Zwischen Code, bezeichnet. Die zweite Stufe ist dann der native Code des Zielrechners. IL-Code Der .NET-Compiler erzeugt den maschinenunabhängigen IL-Code, der von der Entwicklungsumgebung als EXE-Datei erzeugt und in dem Debug-Verzeichnis abgelegt. Nativer Code <=> Common Language Runtime Die endgültige Übersetzung des IL-Codes in die Maschinensprache des Zielrechners erfolgt durch ein Übersetzungsprogramm auf dem Zielrechner. Dieses Programm wird als Common Language Runtime Umgebung – kurz CLR – bezeichnet. - Seite 38 - .NET-Framework & C#.NET 3.1.3 Zusammenfassung Die folgende Grfaik fasst noch einmal die .Net-Struktur und den Kompilierungsvorgang zusammen. - Seite 39 - .NET-Framework & C#.NET 3.1.4 Veröffentlichung von Anwendungen Soll ein Programm an anderer User weiter gegeben, d.h. veröffentlicht werden, reicht es nicht, die exe-Datei mit dem IL-Code zu verteilen, da man nicht sicher sein, dass auf dem Zielrechner alle benötigten DLLs – sprich alle notwendigen Klassen - vorhanden sind. Will man dieses sicherstellen, muss der Weg über die Veröffentlichung von Projekten gegangen werden. Hierbei werden dann alle wichtigen Bibliotheken zusammengestellt und eine Setup-Datei zur automatischen Installation erzeugt. Beim Veröffentlichen von Projekten werden beispielhaft die nachstehenden Dateien erzeugt, die z.B. auf eine CD kopiert werden können. Durch Aufruf der SETUP-Datei werden dann nicht nur die Anwendung auf dem Zielrechner sondern auch die notwendigen und nicht vorhandenen DDLs installiert. - Seite 40 - .NET-Framework & C#.NET 3.2 Die IDE - Visual Studio .NET Die .NET-Welt besteht - wie bereits mehrfach erläutert - aus den beiden Komponenten: .NET-Framework (Rahmenstruktur, welche Klassen usw. bereitstellt) Entwicklungsumgebung Visual Studio (hier programmieren wir) Mit der FCL (Klassenbibliothek) haben wir uns in den vorherigen Kapiteln schon ausführlich beschäftigt. Jetzt steht die IDE - die Entwicklungsumgebung in Visual Studio - im Fokus. Im Gegensatz zur Umgebung .NET ist C# unsere Sprache! Sie funktioniert auch unabhängig von Viusal Studio in alternativen Entwicklungsumgebungen. Ggf. kann das auch ein vollkommen unkomfortabler Editor sein. Der Quellcode muss nur mittels des .NET-Compilers übersetzt werden. 3.2.1 Visual Studio und alternative Entwicklungsumgebungen Visual Studio .NET VS.Net ist die offizielle Entwicklungsumgebung von Microsoft. Hochschulen, die am MSDN AA - Programm von Microsoft teilnehmen, können die VS.Net Software kostenlos an ihre Studenten abgeben. Das ist bei der FHW der Fall. Sie bekommen mit der Einschreibung einen Download-Link wo Sie sich die IDE herunter laden können. Shareware Neben der VS.Net kann eine Anwendung auch mit einem einfachen Editor oder einem Shareware-Programm entwickelt werden. Bei den meisten Shareware-Programmen sind aber Einschränkungen gegenüber der Microsoft-Version gegeben. Die folgenden Websites stellen ein gutes Portal für .NET-Entwickler dar. Dort sind auch Links zu Shareware-Anbietern zu finden. http://www.it-visions.de/ http://www.dotnetframework.de - Seite 41 - .NET-Framework & C#.NET 3.2.2 Aufruf der Entwicklungsumgebung (IDE) in Visual Studio Den Vorgang beim Starten der IDE haben wir schon mehrfach beschrieben und im Video veranschaulicht. Hier noch einmal im Überblick (Onepager für die praktische Arbeit) die wichtigen Fakten zusammen: Startfenster Parameter der Projekt-Erstellung Vorlage Einstellung der Sprachumgebung für die Entwicklung (C#) Einstellung des Projekttyps (Konsole, Windows-Anwendung,...) Name Name des Projektes (auf jeden Fall zu Beginn einstellen) Ort (Speicherort) Dateiverzeichnis für das Root-Sammelverzeichnis des Projektes - Seite 42 - .NET-Framework & C#.NET 3.2.3 Speichern & Portieren von Projekten Datei-Struktur Die nachstehende Abbildung zeigt die Datei-Struktur, die Visual Studio bei einem Konsolen-Projekt anlegt. Diese darf nicht verändert werden, da damit die projektinternen Verweise nicht mehr gültig wären. Ausschließlich der Bezeichner des Root-Verzeichnisses des Projektes auf der obersten Ebene - hier „1_HeWo_Konsole“ - darf geändert werden. Kopieren von Projekten Immer den obersten Ordner des Projektes mit allen Unterverzeichnissen kopieren. Speichern Beim Speichern eines Projektes grundsätzlich immer das gesamte das Projekt gespeichern. Nicht mit Hilfe von „Speichern unter“ Projekte portieren. Portieren von Projekten Projekte müssen ggf. von der Hochschule zu anderen Standorten portiert werden. Die von anderen Office-Anwendungen bekannte Vorgehensweise ist die, dieses über die Option „Speichern unter …“ des Datei-Menüs zu realisieren. Hiervon ist bei Visual Studio Projekte dringend abzuraten, da über diesen Weg immer nur Teile des Projektes auf dem neuen Datenträger gespeichert werden. Gehen Sie daher bitte immer den oben bereits beschriebenen Weg des Kopierens - in diesem Fall des Kopierens auf einen anderen Datenträger. Beachten Sie, dass Sie immer das gesamte Projekt kopieren, also die oberste Verzeichnisebene im Zugriff haben. - Seite 43 - .NET-Framework & C#.NET 3.2.4 Komponenten der IDE Hier werden noch einmal zusammenfassend und als Hilfe bzw. Überblick die für den Einstieg wichtigsten Ansichten der IDE dargestellt. Erläutert wurden Sie großenteils bereits. Standard-Einstellung bei Konsolen-Anwendungen Standard-Einstellung bei Windows-Anwendungen Designer-Ansicht Code-Ansicht Die Code-Ansicht eines Windows-Projektes bedarf keiner weiteren Erläuterung – sie ist identisch mit der Ansicht bei Konsolen-Anwendungen. - Seite 44 - .NET-Framework & C#.NET 3.2.5 Generelle Einstellungen für die IDE Die Ansicht der IDE kann individuell über das Menü Ansicht eingestellt werden. Das Ansichten Menü ist nachstehend abgebildet. Hinter den Menü-Items stehen entsprechenden Tastaturkombinationen. - Seite 45 - .NET-Framework & C#.NET 3.3 C#-Programmierung in Visual Studio .NET 3.3.1 Anweisungen & Blöcke Optische Differenzierungen in Visual Studio Durch den Compiler werden bereits einige optische Differenzierungen vorgenommen. So werden beispielsweise Schlüsselworte in der Farbe dunkelblau und Klassen der Farbe hellblau dargestellt. Eine Übersicht gibt die nachstehende Auflistung. Schlüsselwort: Dunkelblau class Klasse: Hellblau Program Bezeichner: Schwarz faktor1 Kommentar: Grün //Deklarationen Blöcke { } Anweisungen Anweisungsende ; jede Programmanweisung endet mit einem Semikolon möglichst eine Anweisung je Zeile eine Anweisung kann über mehrere Zeilen gehen bei Fortsetzungszeilen, wenn nicht automatisch eingezogen, einziehen der Folgezeile um einen Tabstopp (vier Leerzeichen) zwischen Methoden- und Eigenschaftendefinitionen mindestens eine Leerzeile einfügen grundsätzlich die Standardeinstellung des Code-Editors verwenden (intelligente Einzüge, Einzüge um vier Zeichen, als Leerzeichen gespeicherte Tabstopps). - Seite 46 - .NET-Framework & C#.NET 3.3.2 Kommentare Kommentare haben keine Auswirkung auf den Programmcode. Sie dienen ausschließlich der Erläuterung für den Entwickler. Hilfreich ist dieses wenn man nach einiger Zeit den Code noch einmal überarbeiten muss. Die Kommentare helfen einem dann die der Programmierung zu Grunde liegende Logik wieder zu erinnern. Die Kommentierung von Code kann aber bei der Entwicklung auch anders eingesetzt werden. Durch eine Auskommentierung von Code wird dieser deaktiviert und es kann die Funktionsweise des Programms ohne diese Codezeilen getestet werden. - Seite 47 - .NET-Framework & C#.NET 3.3.3 Konventionen für Bezeichner Bezeichner verwendet man, um selbst erstellten Komponenten wie Variablen, Klassen usw. einen Namen zu geben. nur wenig formale Regeln. einheitliche Konventionen wichtig Übersichtlichkeit des Programms Bearbeitung durch mehrere Personen wichtige formale Regel: Differenzierung von Groß- und Kleinschreibung (test <> Test) Zulässig sind: Buchstaben, Ziffern, Unterstrich Unzulässig: alle anderen Zeichen auch Leerzeichen Bezeichner darf nicht identisch mit Schlüselwort sein Bezeichner darf nicht mit einer Ziffer beginnen Bei den Bezeichnern ist unter. NET die CamelCase-Notation üblich. Alternative Konventionen Namenskonventionen sind Festlegungen für die Schreibweise der Bezeichner. Sie sollen die Lesbarkeit des Codes verbessern. Konventionen können prinzipiell beliebig sein. Es haben sich aber die folgenden Konventionen als Standards entwickelt. Ungarische Notation Kodierung des Typs im Namen: intZaehler (Typ Integer) Kodierung der Verwendung im Namen: qryKunden (Query/Abfrage) Unterstrich Konvention Verwendung von Unterstrichen: kunden_nummer CamelCase Konvention lowerCamelCase (CamelCase): kundenNummer UpperCamelCase (PascalCase): KundenNummer - Seite 48 - .NET-Framework & C#.NET 3.3.4 Änderung von Bezeichnern Werden Bezeichner geändert, wird diese Änderung nicht automatisch im gesamten Code nachvollzogen – was auch so sein muss. Dennoch stellt VS.Net eine Hilfe zum Umbenennen von Bezeichner zur Verfügung. wird das Fenster zum Umbenennen aktiviert Nach dem Umbenennen der Variablen kann der gesamte Code nach dem alten Bezeichner durchsucht und entsprechend ersetzt werden - Seite 49 - .NET-Framework & C#.NET 3.3.5 Anatomie von C#-Anwendungen In diesem Abschnitt soll der Aufbau, die Anatomie, von Konsolen- und Windows-Anwendungen erläutert werden. Als Referenz sei eingangs noch einmal auf die bereits bekannte hierarchische Struktur von Namespace, Klasse und Methode hingewiesen. Diese Struktur ist auch bei den Anwendungstypen unter .Net wiederzufinden. - Seite 50 - .NET-Framework & C#.NET 3.3.5.1Konsolen-Anwendungen Struktur einer Konsolen-Anwendung Die Struktur von Konsolen-Anwendungen ist, wie bereits oben erwähnt, sehr übersichtlich. Diese Anwendung besteht hierarchisch gesehen aus einem Namespace, einer Klasse und einer Methode. Eintrittspunkt (Entry-Point) Main-Methode Jedes Programm muss einen eindeutigen Eintrittspunkt. (Entry-Point) haben. Die Eindeutigkeit muss gegeben sein, damit der Compiler weiß, an welcher Stelle das Programm beginnt. Bei .Net-Programmen ist dieser Eintrittspunkt die Main-Methode. Jedes Programm muss daher diese Main-Methode besitzen und diese darf auch nicht umbenannt werden. Jedes Projekt muss eine Main-Methode als Startpunkt haben. Die Main-Methode stellt den Startpunkt jeder Applikation dar. Der Bezeichner „Main“ darf nicht geändert werden. - Seite 51 - .NET-Framework & C#.NET 3.3.5.2Windows-Anwendungen Ablauflogik beim Aufruf Die nachstrehende Grafik veranschaulicht die Struktur. Ausgangspunkt ist, wie bei allen .Net-Anwendungen, die Main-Methode. In derr Main-Methode wird die Instanz der Form erzeugt, was mittels des Konstruktors der Form erfolgt. Aus dem Konstruktor heraus erfolgt dann der Aufruf der InitializeComponentMethode, die die Objekte der Form erzeugt. Nachstehend die Dateien im Projektexplorer. - Seite 52 - .NET-Framework & C#.NET Form1.Designer.cs - Seite 53 - .NET-Framework & C#.NET Form1.cs Program.cs - Seite 54 - .NET-Framework & C#.NET 3.3.6 Debug-Fenster Das Debugging unter Visual Studio hat im Grunde zwei Zielrichtungen. Zum einen kann man ein Programm Schritt für Schritt durchführen lassen und dabei anhand des Codes überprüfen, ob die Logik des Programmablaufs korrekt ist. Zum anderen hat man während Prozesses die Möglichkeit, sich den Inhalt der Variablen anzeigen zu lassen. 3.3.6.1Vorgehensweisen Einzelschrittmodus Durch den sogenannten Einzelschrittmodus wird ein Programm gestartet und mittels der <F11>-Taste Anweisung für Anweisung abgearbeitet. Break-Points Break-Points können durch Klicken auf die graue Leiste (linksseitig vom Code) gesetzt bzw. gelöscht werden. Das programm kann mit der >f5>Taste gestartet werden und toppt dann beim Break-Point. - Seite 55 - .NET-Framework & C#.NET 3.3.6.2Debug-Ansichten Befindet sich das Programm im Debug-Modus, kann z.B. über das Menü Debuggen -> Fenster das Lokal-Fenster aktiviert werden, welches die Werte der lokalen Variablen zeigt. Möglicherweise ist dies auch bereits automatisch aktiviert. - Seite 56 - .NET-Framework & C#.NET 3.3.6.3Anzeigen von Variablenwerte Debug-Modus mit Lokal-Fenster Sensitive Hilfe - Seite 57 - .NET-Framework & C#.NET 3.3.7 Projektmappen-Explorer & Symbole Projektexplorer Der Projektexplorer stellt die Dateistruktur des Projektes dar, d.h. aus welchen Dateien das Projekt besteht. Zusätzlich werden z.B. unter dem Knoten Verweise die eingebundenen Namespace-Bibliotheken aufgeführt. Auf der obersten Ebene ist das Gesamtprojekt angeordnet. Darunter befinden sich gleichrangig die Verweise die Form1.cs mit der Form1.Designer.cs und der Form1 (mit dem Ergnis-Methoden der Form!) die Program.cs (Formübergreifender Code) - Seite 58 - .NET-Framework & C#.NET Übersicht zentraler Symbole Symbol Beschreibung Symbol Beschreibung Namespace (Namensraum) Methode() oder Funktion Klasse Operator Schnittstelle Eigenschaft Struktur Feld oder Variable Union Ereignis [Event] Enum Konstante TypeDef Enumerationselement Modul Zuordnungselement Erweiterungsmethode Externe Deklaration Delegate Fehler Ausnahme Vorlage Zuordnung Unbekannt Typweiterleitung Additive Signalsymbole Symbol Beschreibung Public. Der Zugriff ist von jeder Position innerhalb dieser <Kein SigKomponente und von jeder Komponente, die darauf vernalsymbol> weist, möglich. Protected. Der Zugriff ist von der enthaltenden Klasse oder dem enthaltenden Typ oder von abgeleiteten Klassen oder Typen möglich. Private. Der Zugriff ist nur innerhalb der enthaltenden Klasse oder des enthaltenden Typs möglich. Versiegelt. Freund/intern. Der Zugriff ist nur über das Projekt möglich. Shortcut. Eine Verknüpfung zum Objekt. - Seite 59 - .NET-Framework & C#.NET B. Programmiersprache Visual C# 4 Exkurs: Klassen für die Konsolen-Programmierung 4.1 Console-Klasse Die Klasse Console beinhaltet eine Reihe statischer Methoden zur Ein- und Ausgabe auf der Konsole. ReadLine() Einlesen der Eingaben aus dem Tastaturpuffer: faktor1 = Console.ReadLine(); WriteLine() Ausgabe des Textes in " " sowie Zeilenvorschub: Console.WriteLine("Multiplikation zweier Zahlen"); Ausgabe des Textes in " " ohne Zeilenvorschub: Console.Write("Multiplikation zweier Zahlen"); 4.2 Convert-Klasse Diese Klasse stellt statische Methoden zur Konvertierung von Daten zur Verfügung. Z.B. Konvertieren Eingabe aus dem Tastaturpuffer in einen Double-Typ: faktor1 = Convert.ToDouble(Console.ReadLine()); - Seite 60 - .NET-Framework & C#.NET 4.3 Formatierung von Ausgaben Beispiel Benutzerdefinierte Zahlenformatierung Die benutzerdefinierte Formatierung ist eine Alternative und erfolgt innerhalb der WriteLine-Methode. Die Grundstruktur sieht dabei wie folgt aus Console.WriteLine ("{0,10:#,##0.00}", Endwert); Der erste Teil der Anweisung "{0,10:#,##0.00}" ist der Formatierungsstring. Die erste Zahl – hier die 0 – gibt den Platzhalter für die später folgende Variable an. Die Ziffern werden von 0 aufsteigend nummeriert, wobei die 0 der ersten Variablen, die 1 der zweiten Variablen usw. zugeordnet werden. Die zweite Zahl – hier die 10 – gibt an, wie viel Stellen für die Ausgabe reserviert werden sollen. Die ersten beiden Parameter werden durch ein Komma getrennt. Nach dem Doppelpunkt erfolgt die Ausgabeformatierung. Das # ist ein Platzhalter für eine beliebige Ziffer. Diese wird unterdrückt, sofern es sich um eine führende Null oder um eine Null nach dem Dezimalkomma handelt. Der Platzhalter 0 steht auch für eine Ziffer, wobei eine führende Null bzw. eine Null nach dem Komma ausgedruckt wird. Der zweite Teil der Anweisung Endwert stellt die Liste der Variablen dar. Sie werden entsprechend der Reihenfolge den Platzhaltern 0, 1 usw. zugeordnet. - Seite 61 - .NET-Framework & C#.NET Formatierungsbeispiele Screenshot Code - Seite 62 - .NET-Framework & C#.NET Erläuterung In der Zeile 35 erfolgt die unformatierte Ausgabe. Man erkennt auf dem Bildschirm dass der Wert 3000 direkt ohne Tausender-Trennung ohne Nachkommastellen ausgegeben wird. In der Zeile 39 erfolgt eine einfache Formatierung. Der Formatierungstring "Produkt : {0,10:N}" ist der erste Teil der Anweisung. Hier wird der Text “Produkt :“ ausgegeben, gefolgt von einem Platzhalter. Der Platzhalter steht immer in geschweiften Klammern innerhalb des Formatierungstrings. Die erste Zahl legt fest, welche Variable aus der Liste nach dem Formatierungsstring ausgegeben werden soll. Die zweite Zahl 10 legt fest wie viel Stellen für die Ausgabe reserviert werden. Als letztes wird durch einen Doppelpunkt getrennt das Format festgelegt. Die Angabe von N legt ein Standardformat fest, dass Zahlen mit Tausender-Trennung und zwei Nachkommastellen ausgibt. In der Zeile 43 ist die Standardformatierung N ersetzt worden durch "#,##0.0000". Dieses ist eine selbst konstruierte Formatierung. Mit Hilfe der Platzhalter # und 0 können beliebige Formatierungen aufgebaut werden. Wichtig ist noch, dass in der amerikanischen Schreibweise dieTausender-Trennung das Komma und die Dezimalt-Tennung der Punkt ist. Das # ist der Platzhalter für eine beliebige Ziffer, der aber führende und nachstehende Nullen ignoriert. Ein Beispiel soll dieses noch einmal veranschaulichen. Soll die Zahl 10 ausgegeben werden, soll auch nur die Zahl 10 und nicht 0.010 auf der Konsole erscheinen. Demgegenüber ist die 0 ein Platzhalter, der führende nachstehende Nullen ausgibt. In diesem Beispiel sind eine Nul vor dem Komma und vier Nachkommastellen mit Nullen verbindlich. In der Zeile 47 erfolgt die Ausgabe mehrerer Werte mithilfe des Standardformats. Zu erkennen ist, dass bei dem ersten Platzhalter erste Zahl eine 0 und bei dem zweiten Platzhalter erste Zahl eine 1 ist. Wie bereits beschrieben, weist die 0 auf den ersten Wert in der nachstehenden Liste, also faktor1. Demzufolge verweist die 1 im zweiten Platzhalter auf die Variable faktor2 und die zwei auf die Variable produkt. - Seite 63 - .NET-Framework & C#.NET 5 Datentypen I Einordnung Programmiersprache .Net-Framework Begründung für unterschiedliche Datentyp Anhand der C#-Referenz erkennt man, dass eine Vielzahl von Datentypen existieren. Hier eine kurze Begründung für deren Notwendigkeit. Speicherung unterschiedlicher Informationen: Zahlen Texte (Ziechenkette = String) Differnzierung numerischer Datentypen: unterschiedlichen Speicherbedarf - Seite 64 - .NET-Framework & C#.NET 5.1 Typen - Common Type System vs. Programmiersprache Typen in der .NET-Klassenbibliothek Typen in der Programmiersprache Grundsatz: Verwendung des Schlüsselwortes - Seite 65 - .NET-Framework & C#.NET 5.2 Differenzierung der Datentypen 5.2.1 Differenzierung der Typen Werttypen primitive Datentypen; (Deklaration ohne Aufruf des Konstrukturs new) Verweistypen Referenztypen - Seite 66 - .NET-Framework & C#.NET 5.2.2 Werttpyen Strukturen Enumerationen - Seite 67 - .NET-Framework & C#.NET 5.3 Datentypen in C# Numerische Typen Bool'sche Typen Alphanumerische Typen - Seite 68 - .NET-Framework & C#.NET Wertebereich von Datentypen Ganzzahlige Typen Gleitkommatpyen - Seite 69 - .NET-Framework & C#.NET 5.4 Methoden von Datentypen Da unter .Net die Datentypen in der Klassenbibliothek implementiert sind verfügen sie im Gegensatz zu anderen Programmiersprachen über Methoden. Methoden des Typs String Die Methode Concat ist eine statische Methode, was an dem roten S in der ersten Spalte erkennbar ist. Diese Methode kann also nur in Verbindung mit der Klasse String verwendet werden. Die Methode ToUpper ist hingegen eine Instanzmethode und kann daher nur mit der Instanz verwendet werden. - Seite 70 - .NET-Framework & C#.NET Beispiel Bei dem folgenden Beispiel sollen zwei in Kleinschreibweise eingegebene Texte in Großschreibweise umgewandelt und verbunden werden. Die Umwandlung erfolgt mit der Methode ToUpper, die Verkettung der beiden Texte mittels der Methode Concat. - Seite 71 - .NET-Framework & C#.NET Die beiden nachstehenden Abbildungen zeigen noch einmal den Unterschied zwischen statischen und Instanz-Methoden. Instanz-Methoden Verwendet man den Bezeichner text1 der Instanz, also die Instanz, stehen auch nur die Instanzmethoden zur Verfügung. Da die Methode ToUpper eine Instanzmethode ist, wird sie hier aufgelistet. Die statische Methode concate steht hier nicht zur Verfügung. Statische Methoden Verwendet man umgekehrt anstatt des Bezeichners der Instanz die zu Grunde liegende Klasse string, so werden die statischen Methoden zur Verfügung gestellt. Die Methode ToUpper ist hier nicht zu finden. - Seite 72 - .NET-Framework & C#.NET 5.5 Literale Beispiele Numerisches Literal faktor1 = 123,45 Alphanumerisches Literal text1 = "Informatik ist toll!" Literale für Zeichenketten (String) Reguläres String-Literal text1 = "Informatik ist toll!!!"; String-Literal mit Anführungszeichen text2 = "Informatik ist \"toll\"!!!"; Literale für boolsche Werte bnLogik = true; Literale für numerische Werte Grundsätzliche ist die Zuweisung von numerischen Literalen sehr einfach: zahl1 = 75; In einer Vielzahl von Fällen gibt es bei der Zuweisung von Literalen keine Probleme, da die numerischen Literale implizit konvertiert werden. So kann z.B. ein ganzzahliger Wert bei der Zuweisung zu einer Variablen vom Typ Double ohne Schwierigkeiten umgewandelt werden. Die Zuweisung numerischer Literale kann dann zu Schwierigkeiten führen, wenn der Definitionsbereichs bei ganzzahligen Variablen und nichtnegativen Variablen zu beachten ist. Die anderen Suffixe sind der nachstehenden Abbildung zu entnehmen. - Seite 73 - .NET-Framework & C#.NET 5.6 Variablen und Konstanten Deklaration von Variablen Eine Variable ist ein über einen Namen ansprechbarer, termporrärer Speicherplatz im Hauptspeicher. int i, test1; Zu beachten sind die in Abschnitt „3.3.3 Konventionen für Bezeichner“ festgelegten Konventionen. Initialisierung von Variablen Durch die obige Anweisung werden Variablen deklariert nicht aber in initialisiert. D.h., dass der Variable kein Initial-Wert zugewiesen wird. Erfolgt dieses auch nicht im weiteren Programm-Verlauf kann es z.B. bei der Ausgabe zu dem nachstehenden Fehler kommen. Gültigkeit von Variablen Eine Variable ist nur in dem durch { } markierten Block einschließlich der untergeordneten Blöcke gültig. - Seite 74 - .NET-Framework & C#.NET Kostante Der Verwendung von Konstanten ist - wie der Name schon besagt - eingeschränkt. Der Inhalt einer Konstanten ist konstant und kann nicht verändert werden. So könnte bspw. die Verwendung einer Konstanten für den MWStSatz in einem Programm sinnvoll sein.wenn man davon ausgeht, dass dieser Steuer-Satz nicht geändert wird und innerhalb des Programmes vor einem versehentlichen Überschreiben gesichert werden soll. Die Deklaration von Konstanten erfolgt durch analog zu Variablen jedoch unter der zusätzlichen Verwendung des Schlüsselwortes const: const int Konstante = 100; Beim Versuch des Überschreibens tritt der folgende Fehler auf. - Seite 75 - .NET-Framework & C#.NET 5.7 Operatoren und Ausdrücke Beispiel In der folgenden Anweisung produkt = a * b; in dieser Programmzeile sind folgende Elemente enthalten: Operator : Multiplikationszeichen „ * “ Ausdruck : „a * b“ Zuweisungsoperator : Gleichheitszeichen „ = “ Zuweisungsoperatoren Das „ = “ wird als Zuweisungsoperator bezeichnet. Es gilt immer: Ziel = Quelle; Der Zuweisungsoperator ist kein mathematisches Gleichheitszeichen. Ein Vertauschen der Seiten zu "Quelle = Ziel" ist nicht zulässig. Der Wert des rechts stehenden Ausdrucks wird der links stehenden Variablen zugewiesen Auf beiden Seiten des Zuweisungsoperators müssen Ausdrücke des gleichen Datentyps stehen (s. auch Typ-Konvertierung) Weitere Zuweisungsoperatoren Operatoren = += -= *= /= %= &= |= ^= <<= >>= ?? Operatoren für die Grundrechenarten - Seite 76 - .NET-Framework & C#.NET Verkürzte Zuweisung Verkürzte Zuweisungen sind eine Kombination des Zuweisungsoperators mit einem Rechenoperator. Die folgende Anweisung i = i + 3; wird dadurch auf diese Schreibweise verkürzt i += 3; Die nachstehenden Darstellungen sind der Publikation aus dem Herdt-Verlag entnommen Inkrementierung und Dekrementierung Logische Vergleichsoperatoren - Seite 77 - .NET-Framework & C#.NET Verknüfungsoperatoren - Seite 78 - .NET-Framework & C#.NET 5.8 Konvertierung von Datentypen Die Konvertierung von Datentypen ist ein zentraler und wichtiger Aspekt der Programmierung. Grundsätzlich gilt, dass auf beiden Seiten des Zuweisungsoperator die gleichen Typen stehen müssen. Ziel = Quelle, Grundsätzlich muss bei unterschiedlichen Datentypen immer konvertiert werden. Es gibt aber eine Ausnahme. Ist der Quelldatentyp eine Untermenge des Zieldatentyps, kann auf eine explizite Konvertierung verzichtet werden. In diesem Fall erfolgt die Konvertierung implizit vom Compiler. Ein Beispiel soll dieses noch mal veranschaulichen. Sei die Variable zahl2 vom Typ Integer und die Variable zahl1 vom Typ double. Dann ist die folgende Anweisung trotz unterschiedlicher Datentypen auf beiden Seiten der Zuweisung korrekt, da der Wertebereich des Typs integer eine Untermenge des Typs double ist. zahl1 = zahl2 (double = interger) Es wird also in der Programmierung zwischen den beiden folgenden Konvertierungsoptionen unterschieden: implizite Konvertierung explizite Konvertierung Implizite Konvertierungen - Seite 79 - .NET-Framework & C#.NET Explizite Konvertierung Bei der expliziten Type-Konvertierung stehen verschiedene Vorgehensweisen zur Verfügung. Explizite Konvertierung durch Zuweisung mit Type-Angabe Explizite Konvertierung durch Methoden der Typ-Strukturen Explizite Konvertierung durch Methoden der Convert-Klasse Verwendung der Type-Angabe bei der Zuweisung Diese Vorgehensweise ist sehr komfortabel, da der Zieldatentyp nur in Klammern für den Ausdruck auf der rechten Seite des Zuweisungsoperators eingefügt werden muss. Zahl1 = (Double) Console.ReadLine(); Leider hat diese Vorgehensweise nicht immer einsetzbar. Wir werden sie sehr intensiv bei der Programmierung von Excel Anwendungen einsetzen Methoden der Typ-Strukturen Des Weiteren stehen die Konvertierungs-Methoden der Datentypen zur Verfügung, wie z.B. die des nachstehenden Typs Decimal. Methoden der Convert-Klasse - Seite 80 - .NET-Framework & C#.NET 6 C#-Anweisungen Einordnung in das .Net-Framework Einordnung in die Programmiersprache C# - Seite 81 - .NET-Framework & C#.NET 6.1 Vom Problem zum Programm Grundsätzliche Vorgehensweise Die grundsätzliche Vorgehensweise bei der Erstellung eines Programms erfolgt in drei Schritten: Problemanalyse Struktogramm Codierung Strukturelemente Um die Logik von Sachverhalten darzustellen gibt es im Wesentlichen nur drei Elemente: Sequenz Alternation IIteration Eine Sequenz sind einfach mehrere Anweisungen, die nacheinander abgearbeitet werden. Eine Alternation ist eine Entscheidung zwischen Alternativen und Iteration eine Wiederholung oder auch Schleife. Betrachtet man einmal alle im Leben oder einem Betrieb auftretende Prozesse, so lassen sich diese immer durch diese drei Strukturelemente darstellen. - Seite 82 - .NET-Framework & C#.NET 6.1.1 Beispiel für Vorgehensweise Grundsätzliche Vorgehensweise Die grundsätzliche Vorgehensweise bei der Erstellung eines Programms erfolgt in drei Schritten: Problemanalyse Struktorgramm Codierung Problemstellung Nach Eingabe der Daten für Anfangskapital, Laufzeit und Zinssatz sollen die Berechnungen durchgeführt und Tabelle ausgegeben werden. Zu beachten ist dabei noch, dass ab dem 5. Jahr ein Bonus von 2% auf Zinsatz gewährt wird. - Seite 83 - .NET-Framework & C#.NET 6.1.1.1Problemanalyse Zu Beginn der Analyse sollten die Berechnungen einmal manuell durchgeführt werden, damit der Rechenweg, also das was programmiert soll, festgelegt ist. Die nachstehende Abbildung zeigt dieses. Vor der Berechnung wird gepürft, ob das akutelle Jahr kleiner oder gleich 5 ist. Danach erfolgt die Berechnung der Zinsen zinsen = 1.000 * 3 / 100 = 30. Abschließend wird das Endkapital berechnung: endkapital = 1.000 + 30 = 1.030 Ab dem 5. Jahr wird der Zinssatz um 2 erhöht; die Berechnungen sind identisch. - Seite 84 - .NET-Framework & C#.NET Um das Ganze in einer strukturierten Form darzustellen sind noch weitere Vorarbeiten notwendig. Als Vorstufe sind die obigen Berechnungen nachstehend mit Variablen-Bezeichnern versehen worden. Aus der Überprüfung 1<=5 wird jetzt aktuellesJahr <= laufZeit Bei den Berechnungen ergibt sich jetzt zinsen = anfangsKapital * zinsSatz / 100 bzw. endKapital = anfangsKapital + zinsen Iteration Im Prinzip dürfte bereits deutlich geworden sein, dass diese Berechnungen entsprechend der Laufzeit wiederholt werden, es sich folglich um eine Schleife - auch Iteration - handelt. - Seite 85 - .NET-Framework & C#.NET Allerdings haben wir noch Probleme mit dem Inhalt der Schleife, dem Schleifenkörper: Die Berechnungen im ersten Jahr lauten: zinsen = anfangsKapital * zinsSatz / 100 endKapital = anfangsKapital + zinsen Die Berechnungen im zweiten Jahr lauten: zinsen = endKapital * zinsSatz / 100 endKapital = endKapital + zinsen Im Grunde sind diese Berechnungen identisch, können aber so noch nicht vereinheitlicht werden, da im ersten Jahr mit der Variablen anfangsKapital und im zweiten Jahr mit der Variablen endKapial gerechnet werden muss. Würde man sich entscheiden nur mit den Anweisung des ersten Jahres zu arbeiten gibt es ab dem zweiten Jahr ein Problem; entscheidet man für die Anweisungen des zweiten Jahres gibt es im ersten Jahr ein Problem. Dieser Konflikt lässt sich lösen, wenn man vor der Schleife einmal die Anweisung endKapital = anfangsKapital einschiebt. Damit hat die Variable endKapital einen Startwert und es kann in der Schleife immer die Logik des zweiten Jahres verwendet werden. Alternation Ein weiteres Problem stellt die modifizierte Berechnung ab dem fünften Jahr dar. In disem Fall wird der Zinssatz um 2% erhöht. Diese Struktur wird als Alternation bezeichnet. Bei der Berechnung der Zinsen gibt es folglich abhängig von dem aktuellen Jahr eine unterschiedliche Berechnung. - Seite 86 - .NET-Framework & C#.NET 6.1.1.2Struktogramm Ein Struktogramm ist die komprimierte Darstellung der Logik eines Programms. Für Sequenzen, Alternationen und Iteration sind bestimmte Symbole definiert. Das folgende Struktogramm entsteht eigneltich in mehreren Schritten; diesen Prozess können wir in einem Skript nicht darstellen. Es sei daher auf das entsprechende Video verwiesen. - Seite 87 - .NET-Framework & C#.NET 6.1.1.3Codierung Als Basis für die Programmierung dient jetzt das Struktogramm. Dieses vor Augen kann jetzt Zeile für Zeile das Struktogramm in Code umgesetzt werden. Dabei kann eine Sequenz des Struktogramms durchaus mehrere Zeilen im Code umfassen. Die Eingabe bspw. geht von Zeile 17 bis zur Zeile 29. - Seite 88 - .NET-Framework & C#.NET 6.1.2 Grundsätzliches zur Problemanalyse Die Anaylse ist die wichtigste Phase in der Entwicklung. Die Auseinandersetzung mit der Logik einer Problemstelung und deren Darstellung in kompakter, grafischer Form ist elementar. Das Prinzip lautet dabei: Reduktion des Schwierigkeitsgrades PAP NSD Fazit Das Struktogramm ist heute die wohl am häufigsten eingesetzt Darstellungsform. Dennoch scheint es in bei komplexen Ablaufstrukturen sinnvoll, den PAP additiv zu verwenden. - Seite 89 - .NET-Framework & C#.NET 6.1.3 Kontrollstrukturen Die nachstehende Abbildung stellt die Inhalte der folgenden Kapitel in grafischer Form dar. Wir werden diese Aspekte, beginnend mit den Verzweigungen, auch Alternationen, und darauf folgend den Schleifen, auch Iterationen, bearbeiten. - Seite 90 - .NET-Framework & C#.NET 6.2 Kontrollstrukturen Die nachstehende Abbildung stellt die Inhalte der folgenden Kapitel in grafischer Form dar. Wir werden diese Aspekte, beginnend mit den Verzweigungen, auch Alternationen, und darauf folgend den Schleifen, auch Iterationen, bearbeiten. 6.2.1 Alternationen (Verzweigungen) In dem nun folgenden Kapiteln werden die Verzweigungen, in der Grafik noch einmal deutlich gemacht, systematisch erläutert. - Seite 91 - .NET-Framework & C#.NET 6.2.1.1Einseitige Auswahl Syntax Die einseitige Alternation hat die folgende Syntax. Beschreibung Bedingung: ein oder mehrere Ausdrücke der beiden folgenden Arten: Ein numerischer Ausdruck oder ein Zeichenfolgenausdruck, der True oder False ergibt. Bei der Verknüpfung mehrerer Bedingungen können diese mit logischen Operatoren verknüpft werden. Enthält der if-Block nur eine Anweisung, kann auf die Blockung durch { } verzichtet werden. NSD Im NSD wird eine eineitige Alternation wie folgt dargestellt. Da nur das Symbol für eine zweiseitige Alternation existiert, wird der nein-Block entwertet. - Seite 92 - .NET-Framework & C#.NET Beispiel Problemstellung Zu erstellen ist ein C#-Programm, das anhand des Bruttoumsatzes den Rabatt und den Nettoumsatz bestimmt. Dabei gelten folgende Bedingungen: bis 1000,- € Umsatz wird kein Rabatt gewährt ab 1000,- € Umsatz wird ein Rabatt von 10% gewährt Screenshot NSD - Seite 93 - .NET-Framework & C#.NET Code //Deklarationen double bruttoPreis, nettoPreis, rabatt; //Prozedur //Eingabe Console.WriteLine("Rabatt‐Berechnung"); Console.WriteLine("*****************"); Console.WriteLine(); Console.Write("Brutto‐Preis: "); bruttoPreis = Convert.ToDouble(Console.ReadLine()); //Berechnung rabatt = 0; if(bruttoPreis>=1000) { rabatt=bruttoPreis * 0.1; } nettoPreis = bruttoPreis ‐ rabatt; //Ausgabe Console.WriteLine(); Console.WriteLine("Brutto‐Preis : {0,12:N}", bruttoPreis); Console.WriteLine("Rabatt : {0,12:N}", rabatt); Console.WriteLine("Netto Preis : {0,12:N}", nettoPreis); Console.ReadLine(); - Seite 94 - .NET-Framework & C#.NET 6.2.1.2Zweiseitige Auswahl Syntax Die zweiseitige Alternation hat die folgende Syntax. Beschreibung Bedingung: ein oder mehrere Ausdrücke der beiden folgenden Arten: Ein numerischer Ausdruck oder ein Zeichenfolgenausdruck, der True oder False ergibt. Bei der Verknüpfung mehrerer Bedingungen können diese mit logischen Operatoren verknüpft werden. Enthält der if- oder else-Block nur eine Anweisung, kann auf die Blockung durch { } verzichtet werden. NSD Im NSD wird eine eineitige Alternation wie folgt dargestellt. Da nur das Symbol für eine zweiseitige Alternation existiert, wird der nein-Block entwertet. - Seite 95 - .NET-Framework & C#.NET Problemstellung Zu erstellen ist ein C#-Programm, das anhand des Bruttoumsatzes den Rabatt und den Nettoumsatz bestimmt. Dabei gelten folgende Bedingungen: bis 1000,- € Umsatz wird ein Rabatt von 10% gewährt ab 1000,- € Umsatz wird ein Rabatt von 20% gewährt Screenshot NSD - Seite 96 - .NET-Framework & C#.NET Code //Deklarationen double bruttoPreis, nettoPreis, rabatt; //Prozedur //Eingabe Console.WriteLine("Rabatt‐Berechnung"); Console.WriteLine("*****************"); Console.WriteLine(); Console.Write("Bruoot‐Preis: "); bruttoPreis = Convert.ToDouble(Console.ReadLine()); //Berechnung if (bruttoPreis < 1000) { rabatt = bruttoPreis * 0.1; } else { rabatt = bruttoPreis * 0.2; } nettoPreis = bruttoPreis ‐ rabatt; //Ausgabe Console.WriteLine(); Console.WriteLine("Brutto‐Preis : {0,12:N}", bruttoPreis); Console.WriteLine("Rabatt : {0,12:N}", rabatt); Console.WriteLine("Netto Preis : {0,12:N}", nettoPreis); Console.ReadLine(); - Seite 97 - .NET-Framework & C#.NET 6.2.1.3Mehrseitige Auswahl Syntax Beschreibung Der Selektor ist i.d.R. eine Variable, deren Wert bei den verschiedenen caseFällen abgeprüft wird. Führt eine case-Prüfung zu einer wahren Bedingung, so werden die nach der case-Anweisung stehenden Anweisungen ausgeführt. Zwei case-Anweisungen dürfen jedoch nicht denselben Wert aufweisen. Die Ausführung des Anweisungstexts beginnt mit der ausgewählten Anweisung und wird fortgesetzt, bis die break-Anweisung dem case-Text die Steuerung entzieht. Nach jedem case-Block muss eine Sprunganweisung, wie break, stehen. Dies gilt auch für den letzten Block, unabhängig davon, ob er eine caseAnweisung oder eine default-Anweisung enthält. NSD - Seite 98 - .NET-Framework & C#.NET Problemstellung Das Kindergeld beträgt in Deutschland gemäß § 66 Abs. 1 EStG für das erste, zweite und dritte Kind jeweils 154,00 Euro monatlich und für das vierte und jedes weitere Kind 179,00 Euro monatlich (Stand: 20.12.2007). Das nachfolgende Programm soll in Abhängigkeit von der Kinderzahl die monatliche bzw. jährliche Kindergeldzahlung berechnen. Screenshot NSD - Seite 99 - .NET-Framework & C#.NET Code //Dekalrationen Double kinderGeld, kinderGeldJahr; Int16 anzahlKinder; //Prozedur //Eingabe Console.Clear(); Console.WriteLine("Kindergeld‐Berechnung"); Console.WriteLine("****************"); Console.WriteLine(); Console.Write("Anzahl Kinder : "); anzahlKinder = Convert.ToInt16(Console.ReadLine()); //Berechnungen switch (anzahlKinder) { case 0: kinderGeld = 0; break; case 1: kinderGeld = 154; break; case 2: kinderGeld = 308; break; case 3: kinderGeld = 462; break; default: kinderGeld = 3 * 154 + (anzahlKinder ‐ 3) * 179; break; } kinderGeldJahr = kinderGeld * 12; //Ausgabe Console.WriteLine(); Console.WriteLine("Kindergeld p.m. : {0,10:N}", kinderGeld); Console.WriteLine("Kindergeld p.a. : {0,10:N}", kinderGeldJahr); Console.ReadLine(); - Seite 100 - .NET-Framework & C#.NET 6.2.1.4Mehrstufige Auswahl Syntax Beschreibung Die mehrstufige Auswahl ist - wie die Bezeichnung bereits sagt – eine gestufte Fallunterscheidung, was auch das unten abgebildete Struktogramm zeigt. Wenn folglich eine Bedingung mit true entschieden wird, werden die nachfolgenden Bedingungen nicht mehr geprüft. Umgekehrt werden bei einer mehrstufigen Auswahl ggf. alle Bedingungen durchgeprüft. Letzteres ist der wesentliche Unterschied zur im folgenden Abschnitt dargestellten mehrseitigen Auswahl. NSD - Seite 101 - .NET-Framework & C#.NET Problemstellung Zu erstellen ist ein C#-Programm, das anhand des Bruttoumsatzes den Rabatt und den Nettoumsatz bestimmt. Dabei gelten folgende Bedingungen: bis 1.000,- € Umsatz wird 10% Rabatt gewährt ab 1.000,- € Umsatz wird 20% Rabatt gewährt ab 2.000,- € Umsatz wird 30% Rabatt gewährt ab 3.000,- € Umsatz wird 40% Rabatt gewährt Screenshot NSD - Seite 102 - .NET-Framework & C#.NET Code //Deklarationen double bruttoPreis, nettoPreis, rabatt; //Prozedur //Eingabe Console.WriteLine("Rabatt‐Berechnung"); Console.WriteLine("*****************"); Console.WriteLine(); Console.Write("Bruoot‐Preis: "); bruttoPreis = Convert.ToDouble(Console.ReadLine()); //Berechnung if (bruttoPreis < 1000) { rabatt = bruttoPreis * 0.1; } else { if (bruttoPreis < 2000) { rabatt = bruttoPreis * 0.2; } else { if (bruttoPreis < 3000) { rabatt = bruttoPreis * 0.3; } else { rabatt = bruttoPreis * 0.4; } } } nettoPreis = bruttoPreis ‐ rabatt; //Ausgabe Console.WriteLine(); Console.WriteLine("Brutto‐Preis : {0,12:N}", bruttoPreis); Console.WriteLine("Rabatt : {0,12:N}", rabatt); Console.WriteLine("Netto Preis : {0,12:N}", nettoPreis); Console.ReadLine(); - Seite 103 - .NET-Framework & C#.NET 6.2.2 Iterationen Die Iterations-Anweisungen oder Schleifen stellen einen weiteren wichtigen Bereich der Kontrollstrukturen dar und werden im Folgenden erläutert. Grundsätzlich gibt es Schleifen, deren Anzahl an Schleifen-Durchläufen durch einen Zähler bestimmt werden und Schleifen, die durch eine logische Bedingung – z.B. solang der Restwert > 0 ist – gesteuert werden. Bei letzteren kann man wiederum, in Abhängig davon wo die Prüfung erfolgt zum Beginn oder zum Ende der Schleife – in kopf- oder fußgesteuerte Schleifen differenzieren. - Seite 104 - .NET-Framework & C#.NET 6.2.2.1Zählergesteuerte Iteration Syntax Beschreibung Schleifenkopf counter = startwert counter ist eine numerische Variable, der zu Beginn der Schleife ein startwert zugwiesen wird, bei der die Zählung beginnt. condition condition ist eine Bedingung, die das Abbruchkriterium der Schleife formuliert. I.d.R. ist das eine < oder <= Abfrage auf den Endwert. nextStatement ist eine Anweisung, die den Algorythmus zur Berechnung des nächsten Zählerwertes festlegt. Schleifenkörper eine oder mehrere Anweisungen NSD - Seite 105 - .NET-Framework & C#.NET Problemstellung Bei der vorliegenden Problemstellung, soll nach Eingabe des Anfangskapitals, des Zinssatzes und der Laufzeit die Entwicklung des Kapitels dargestellt werden. Screenshot NSD - Seite 106 - .NET-Framework & C#.NET Code //Deklarationen double kapitalStart, kapitalEnde, zinsSatz; int laufzeit, zaehler; //Prozedur //Eingabe Console.WriteLine("Kapital‐Entwicklung"); Console.WriteLine("*******************"); Console.WriteLine(); Console.Write("Start‐Kapital : "); kapitalStart = Convert.ToDouble(Console.ReadLine()); Console.Write("Zinssatz : "); zinsSatz = Convert.ToDouble(Console.ReadLine()); Console.Write("Laufzeit : "); laufzeit = Convert.ToInt16(Console.ReadLine()); //Berechnung & Ausgabe Console.WriteLine(); Console.WriteLine("{0,4} {1,10}", "Jahr", "Kapital"); Console.WriteLine("****************"); kapitalEnde = kapitalStart; for (zaehler = 1; zaehler <= laufzeit; zaehler++) { kapitalEnde = kapitalEnde * (1 + zinsSatz / 100); Console.WriteLine("{0,4} {1,10:N}", zaehler, kapitalEnde); } Console.ReadLine(); - Seite 107 - .NET-Framework & C#.NET Problemstellung Zu erstellen ist ein C#-Programm, das durch zwei zählergesteuerte Schleifen eine 1 X 1 Tabelle erzeugt. Durch die Eingabe von Startwert, Endwert und Schrittweite kann der Schleifendurchlauf bestimmt werden. Bei der ersten Version soll die Schleife aufsteigend durchlaufen werden, bei der zweiten Version absteigend. Screenshot NSD - Seite 108 - .NET-Framework & C#.NET Code 1 //Deklarationen double produkt; int start, ende, step, i, j; //Prozedur //Eingabe Console.Clear(); Console.WriteLine("1 * 1 ‐ Tabelle"); Console.WriteLine("***************"); Console.WriteLine(); Console.Write("Startwert : "); start = Convert.ToInt16(Console.ReadLine()); Console.Write("Endwert : "); ende = Convert.ToInt16(Console.ReadLine()); Console.Write("Schrtittweite : "); step = Convert.ToInt16(Console.ReadLine()); //Berechnungen und Ausgabe Console.WriteLine(); Console.WriteLine(); for (i = start; i <= ende; i = i + step) { for (j = 1; j <= 10; j++) { produkt = i * j; Console.Write("{0,4}", produkt); } Console.WriteLine(); } Console.ReadLine(); Code 2 for (i = ende; i > start; i = i ‐ step) { for (j = 1; j <= 10; j++) { produkt = i * j; Console.Write("{0,4}", produkt); } Console.WriteLine(); } - Seite 109 - .NET-Framework & C#.NET 6.2.2.2 Bedingte Iteration - kopfgesteuert Syntax Beschreibung Schleifenkopf condition condition ist eine logische Bedingung, die das Wiederholungskriterium der Schleife formuliert. Schleifenkörper eine oder mehrere Anweisungen jeweils vor Durchführung der Anweisung wird eine Bedingung geprüft. NSD - Seite 110 - .NET-Framework & C#.NET Problemstellung Zu erstellen ist ein C#-Programm, das nach Eingabe des Anschaffungswertes und des Abschreibungssatzes den Restwertverlauf darstellt. Der Programmablauf soll über eine kopfgesteuerte Schleife realisiert werden. Bei der Formulierung des Abbruchkriteriums, ist auf die Vermeidung von "Endlosschleifen" zu achten. Screenshot NSD - Seite 111 - .NET-Framework & C#.NET Code //Deklarationen double aw, rw, afaSatz, afaBetrag; int jahr; //Prozedur //Eingabe Console.WriteLine("Degressive Abschreibung"); Console.WriteLine("***********************"); Console.WriteLine(); Console.Write("Anschaffungswert : "); aw = Convert.ToDouble(Console.ReadLine()); Console.Write("AFA‐Satz : "); afaSatz = Convert.ToDouble(Console.ReadLine()); //Berechnung & Ausgabe Console.WriteLine(); Console.WriteLine("{0,4} {1,10}", "Jahr", "Restwert"); Console.WriteLine("****************"); rw = aw; jahr = 0; Console.WriteLine("{0,4} {1,10:N}", jahr, rw); while (rw > 100) { jahr++; afaBetrag = rw * afaSatz / 100; rw ‐= afaBetrag; onsole.WriteLine("{0,4} {1,10:N}", jahr, rw); } Console.ReadLine(); - Seite 112 - .NET-Framework & C#.NET 6.2.2.3Bedingte Iteration - fußgesteuert Syntax Beschreibung Schleifenfuß condition condition ist eine logische Bedingung, die das Wiederholungskriterium der Schleife formuliert. Schleifenkörper eine oder mehrere Anweisungen Die Anweisung wird mind. 1x durchgeführt. Erst nach einer Durchführung wird geprüft. NSD - Seite 113 - .NET-Framework & C#.NET Problemstellung Das bereits bekannt Programm ist so zu programmieren, dass die Schleife fußgesteuert wird. NSD - Seite 114 - .NET-Framework & C#.NET Code //Deklarationen double aw, rw, afaSatz, afaBetrag; int jahr; //Prozedur //Eingabe Console.WriteLine("Degressive Abschreibung"); Console.WriteLine("***********************"); Console.WriteLine(); Console.Write("Anschaffungswert : "); aw = Convert.ToDouble(Console.ReadLine()); Console.Write("AFA‐Satz : "); afaSatz = Convert.ToDouble(Console.ReadLine()); //Berechnung & Ausgabe Console.WriteLine(); Console.WriteLine("{0,4} {1,10}", "Jahr", "Restwert"); Console.WriteLine("****************"); rw = aw; jahr = 0; Console.WriteLine("{0,4} {1,10:N}", jahr, rw); do { jahr++; afaBetrag = rw * afaSatz / 100; rw ‐= afaBetrag; Console.WriteLine("{0,4} {1,10:N}", jahr, rw); } while (rw > 100); Console.ReadLine(); - Seite 115 - .NET-Framework & C#.NET 6.3 Übungen 6.3.1 Endwertmethode Problemstellung Zu erstellen ist ein Programm zur Darstellung der Endwert-Entwicklung einer Investition bei den entsprechenden Eingaben. Screenshot NSD - Seite 116 - .NET-Framework & C#.NET Code //Deklarationen double investition, cashFlow, endWert, zinsSatz, zinsen; int laufzeit, jahr; //Prozedur //Eingabe Console.WriteLine("Endwert‐Methode"); Console.WriteLine("*******************"); Console.WriteLine(); Console.Write("Investition : "); investition = Convert.ToDouble(Console.ReadLine()); Console.Write("CashFlow : "); cashFlow = Convert.ToDouble(Console.ReadLine()); Console.Write("Zinssatz : "); zinsSatz = Convert.ToDouble(Console.ReadLine()); Console.Write("Laufzeit : "); laufzeit = Convert.ToInt16(Console.ReadLine()); //Berechnungen & Ausgabe Console.WriteLine(); endWert = investition * (‐1); for (jahr = 1; jahr <= laufzeit; jahr++) { zinsen = endWert * zinsSatz / 100; endWert = endWert + zinsen + cashFlow; Console.WriteLine("{0,4} {1,10:N} {2,10:N} {3,10:N}", jahr, cashFlow, zinsen, endWert); } Console.ReadLine(); - Seite 117 - .NET-Framework & C#.NET 6.3.2 Degressive Abschreibung 1 Problemstellung Zu erstellen ist ein Programm, das in etwas vereinfachter Form eine Tabelle für eine degressive Abschreibung darstellt. Dabei existieren vorerst die folgenden Eingabegrößen: Anschaffungswert Degressiver Abschreibungssatz Abbruchkriterium Eine Überprüfung des Abschreibungssatzes erfolgt vorerst nicht. Das Abbruchkriterium ist notwendig, um nicht bis zum Restwert = 0 abschreiben zu müssen, was eine Endlosschleife mit Systemabbruch zur Folge hätte. Screenshot NSD - Seite 118 - .NET-Framework & C#.NET Code //Deklarationen double aw, anfangsWert, restWert, afaSatz, afaBetrag, abbruchKriterium; int jahr; //Prozedur //Eingabe Console.WriteLine("Degressive Abschreibung"); Console.WriteLine("***********************"); Console.WriteLine(); Console.Write("Anschaffungswert : "); aw = Convert.ToDouble(Console.ReadLine()); Console.Write("AfaSatz : "); afaSatz = Convert.ToDouble(Console.ReadLine()); Console.Write("AbbruchKriterium : "); abbruchKriterium = Convert.ToDouble(Console.ReadLine()); //Berechnungen & Ausgabe Console.WriteLine(); Console.WriteLine("{0,4} {1,10} {2,10} {3,10}", "Jahr", "Anfang", "AFA", "Restwert"); Console.WriteLine("*************************************"); Console.WriteLine("{0,4} {1,10:N} {2,10:N} {3,10:N}", 0, 0, 0, aw); jahr = 1; anfangsWert = aw; while (anfangsWert > abbruchKriterium) { afaBetrag = anfangsWert * afaSatz / 100; restWert = anfangsWert ‐ afaBetrag; Console.WriteLine("{0,4} {1,10:N} {2,10:N} {3,10:N}", jahr, anfangsWert, afaBetrag, restWert); anfangsWert = restWert; jahr++; } Console.ReadLine(); - Seite 119 - .NET-Framework & C#.NET 6.3.3 Degressive Abschreibung 2 Problemstellung Das bekannte Programm zur degressiven Abschreibung ist wie folgt zu modifizieren. Zu berücksichtigen sind die Eingabegrößen: Anschaffungswert, Nutzungsdauer und Abbruchkriterium Anhand der Nutzungsdauer ist der AfA-Satz zu bestimmen. Dabei ist der degressive Afa-Satz das 2-fache linearen Afa-Satzes, maximal aber 20%. Der lineare AfA-Satz wird berechnet durch Screenshot NSD - Seite 120 - .NET-Framework & C#.NET Code //Deklarationen double aw, anfangsWert, restWert, afaSatzL, afaSatzD, afaBetrag, abbruchKriterium; int jahr, laufzeit; //Prozedur //Eingabe Console.WriteLine("Degressive Abschreibung"); Console.WriteLine("***********************"); Console.WriteLine(); Console.Write("Anschaffungswert : "); aw = Convert.ToDouble(Console.ReadLine()); Console.Write("Laufzeit : "); laufzeit = Convert.ToInt16(Console.ReadLine()); Console.Write("AbbruchKriterium : "); abbruchKriterium = Convert.ToDouble(Console.ReadLine()); //Berechnungen //Afa‐Satz afaSatzL = 100 / laufzeit; if (afaSatzL * 2 > 20) afaSatzD = 20; else afaSatzD = afaSatzL * 2; Console.WriteLine(); Console.WriteLine("AfaSatz degressiv : {0,4:N}%", afaSatzD); Console.WriteLine(); //Tabellenbeschrfitung Console.WriteLine(); Console.WriteLine("{0,4} {1,10} {2,10} {3,10}", "Jahr", "Anfang", "AFA", "Restwert"); Console.WriteLine("*************************************"); Console.WriteLine("{0,4} {1,10:N} {2,10:N} {3,10:N}", 0, 0, 0, aw); //Restwertberechung & Ausgabe jahr = 1; anfangsWert = aw; while (anfangsWert > abbruchKriterium) { afaBetrag = anfangsWert * afaSatzD / 100; restWert = anfangsWert ‐ afaBetrag; Console.WriteLine("{0,4} {1,10:N} {2,10:N} {3,10:N}", jahr, anfangsWert, afaBetrag, restWert); anfangsWert = restWert; jahr++; } - Seite 121 - .NET-Framework & C#.NET 6.3.4 Prämienberechnung Problemstellung Zu erstellen ist ein Programm für die Berechnung von Prämien, die in Abhängigkeit vom Bruttogehalt und der Betriebszugehörigkeit berechnet werden. Es gelten die folgenden Modalitäten: Betriebszugehörigkeit Prämie 0 bis < 1 1 bis < 3 3 bis < 10 sonst 10% 30% 50% 100% Zusätzlich sind die folgenden Restriktionen zu beachten: minimale Prämie 100,- € maximale Prämie 2.000,- € Ferner ist die Einagbe auf Plausibilität zu prüfen. Screenshot - Seite 122 - .NET-Framework & C#.NET NSD - Seite 123 - .NET-Framework & C#.NET Code //Deklarationen double gehalt, praemie, summe, jahre; //Prozedur //Eingabe Console.Clear(); Console.WriteLine("Prämien‐Berechnung"); Console.WriteLine("******************"); Console.WriteLine(); Console.Write("Gehalt : "); gehalt = Convert.ToDouble(Console.ReadLine()); Console.Write("Betriebszugehöirgkeit : "); jahre = Convert.ToDouble(Console.ReadLine()); //Eingabe‐Überprüfung if (gehalt <= 0 | jahre <= 0) { Console.WriteLine(); Console.WriteLine("falsche Eingabe ..."); Console.ReadLine(); return; } //Berechnung if (jahre < 1) praemie = gehalt * 0.1; else if (jahre < 3) praemie = gehalt * 0.3; else if (jahre < 10) praemie = gehalt * 0.5; else praemie = gehalt; if (praemie < 100) praemie = 100; if (praemie > 2000) praemie = 2000; summe = gehalt + praemie; //Ausgabe Console.WriteLine(); Console.WriteLine("Gehalt : {0,10:N}", gehalt); Console.WriteLine("Prämie : {0,10:N}", praemie); Console.WriteLine("Gesamtbetrag : {0,10:N}", summe); Console.ReadLine(); - Seite 124 - .NET-Framework & C#.NET 6.3.5 Zinsrechnung Problemstellung Das nachstehende Programm stellt ein Menü für die Varianten der Zinsrechnung dar, da alle aus der Grundformel abgeleitet sind: Screenshot Menü Fehlermeldung bei unzulässiger Eingabe Message beim Programmende Eingabe & Ausgabe bei „Berechnung der Zinsen“ - Seite 125 - .NET-Framework & C#.NET NSD - Seite 126 - .NET-Framework & C#.NET Code //Deklarationen double zinsen, kapital, zinsSatz; int tage, auswahl; //Prozedur do { //BildschirmAufbau Console.Clear(); Console.WriteLine("Menü für Zinsrechnung"); Console.WriteLine("*********************"); Console.WriteLine(); Console.WriteLine("Zinsen : 1"); Console.WriteLine("Kapital : 2"); Console.WriteLine("Prozentsatz : 3"); Console.WriteLine("Tage : 4"); Console.WriteLine(); Console.WriteLine("Abbruch : 0"); Console.WriteLine(); Console.Write("Eingabe : "); auswahl = Convert.ToInt16(Console.ReadLine()); //Berechnungen & Ausgabe switch (auswahl) { case 0: Console.Clear(); Console.WriteLine("Ende ‐ weiter mit Return"); Console.ReadLine(); break; case 1: //Bildschirmaufbau & Eingabe Console.Clear(); Console.WriteLine("Berechnung der Zinsen"); Console.WriteLine("*********************"); Console.WriteLine(); Console.Write("Kapital : "); kapital = Convert.ToDouble(Console.ReadLine()); Console.Write("Prozentsatz : "); zinsSatz = Convert.ToDouble(Console.ReadLine()); Console.Write("Tage : "); tage = Convert.ToInt16(Console.ReadLine()); //Berechnung zinsen = (kapital * zinsSatz * tage) / (100 * 360); - Seite 127 - .NET-Framework & C#.NET //Ausgabe Console.WriteLine(); Console.WriteLine("Zinsen {0,12:N}", zinsen); Console.WriteLine(); Console.WriteLine("weiter mit Return"); Console.ReadLine(); break; case 2: //Bildschirmaufbau & Eingabe Console.Clear(); Console.WriteLine("Berechnung des Kapitals"); Console.WriteLine("*********************"); Console.WriteLine(); Console.Write("Zinsen : "); zinsen = Convert.ToDouble(Console.ReadLine()); Console.Write("Prozentsatz : "); zinsSatz = Convert.ToDouble(Console.ReadLine()); Console.Write("Tage : "); tage = Convert.ToInt16(Console.ReadLine()); //Berechnung kapital = (zinsen * 100 * 360) / (zinsSatz * tage); //Ausgabe Console.WriteLine(); Console.WriteLine("Kapital {0,12:N}", kapital); Console.WriteLine(); Console.WriteLine("weiter mit Return"); Console.ReadLine(); break; case 3: //Bildschirmaufbau & Eingabe Console.Clear(); Console.WriteLine("Berechnung des Zinssatzes"); Console.WriteLine("*************************"); Console.WriteLine(); Console.Write("Zinsen : "); zinsen = Convert.ToDouble(Console.ReadLine()); Console.Write("Kapital : "); kapital = Convert.ToDouble(Console.ReadLine()); Console.Write("Tage : "); tage = Convert.ToInt16(Console.ReadLine()); - Seite 128 - .NET-Framework & C#.NET //Berechnung zinsSatz = (zinsen * 100 * 360) / (kapital * tage); //Ausgabe Console.WriteLine(); Console.WriteLine("Zinssatz {0,12:N}", zinsSatz); Console.WriteLine(); Console.WriteLine("weiter mit Return"); Console.ReadLine(); break; case 4: //Bildschirmaufbau & Eingabe Console.Clear(); Console.WriteLine("Berechnung der Laufzeit"); Console.WriteLine("***********************"); Console.WriteLine(); Console.Write("Zinsen : "); zinsen = Convert.ToDouble(Console.ReadLine()); Console.Write("Kapital : "); kapital = Convert.ToDouble(Console.ReadLine()); Console.Write("Zinssatz : "); zinsSatz = Convert.ToInt16(Console.ReadLine()); //Berechnung tage = Convert.ToInt16((zinsen * 100 * 360) / (kapital * zinsSatz)); //Ausgabe Console.WriteLine(); Console.WriteLine("Tage {0,12:N}", tage); Console.WriteLine(); Console.WriteLine("weiter mit Return"); Console.ReadLine(); break; default: Console.Clear(); Console.WriteLine("falsche Eingabe ‐ weiter mit Return"); Console.ReadLine(); break; } } while (auswahl != 0); - Seite 129 - .NET-Framework & C#.NET 7 Datentypen II - Array Bei den bisherigen Variablen konnten in einer Variable immer nur ein Wert gespeichert werden. Hatte man beispielsweise eine Variable endWert vom Typ double, so konnte dort eine relle Zahl abgelegt werden. Diese recht einfache Struktur ist aber bei größeren Datenmengen sehr unflexibel. Achtung: Wann immer Berechnungen durchgeführt werden sollen, ist ein Array nötig. Es speichert Daten (z.B. aus einer Tabelle) eines Datentyps (z.B. double). Bei der nachstehenden Anwendung werden bei drei Filialen die Umsätze für das erste und zweite Halbjahr summiert. Hierfür müssten alleine für die Umsätze 6 Variablen und für die Summen weitere 6 Variabelen dekalriert werden. Komplizierte wird es, wenn beispielsweise die Anzahl der Filialen flexibel sein soll und diese erste nach dem Start des programms durch den Anwender angegeben werden. Damit ist während der Entwicklung die Anzahl der Variablen nicht bekannt. Alle diese Schwierigkeiten lassen sich mittels eines Arrays elegant lösen. - Seite 130 - .NET-Framework & C#.NET 7.1 Grundsätzliches zum Array Struktur eines Arrays Das Array basiert immer auf einem Basistyp, z.B. dem Typ double, string usw. Ein Mischen von Typen innerhalb eines Arrays ist daher nicht möglich. Will man in einem Array alphanumerische Daten speichern, so geht das nur mit dem Typ string; allerdings kann man dann auch nicht mit den Daten rechnen. Ist letzteres erforderlich, so benötigt man einen numerischen Typ, beispielsweise den Typ double, kann dann aber keine alphabethischen Daten speichern. Ein Array kann man sich anschaulich als ein- oder zweidimensionale Matrix vorstellen. Das Array besitzt, wie alle Variabeln, einen Bezeichner. Für den Bezeichner gelten die üblichen Konventionen. Eine einfache Variable wird direkt über den Bezeichner angesprochen. Da dieser Bezeichner nur eine Speichermöglichkeit hat, sind keine weiteren Angaben notwendig. Im Falle eines Arrays ist das etwas anders, da mehrere Speichermöglichkeiten unter dem Bezeichner existieren. Die Speicherplätze eines Arrays werde systemseitig automatisch mit 0 beginnend durchnummeriert. Dieser Index wird dann in eckigen Klammner [ ] nach dem Variablenbezeichner angegeben. Eindimensionales Array Bezeichner des Arrays: namen Zuweisung: namen[0]="Meier"; Lesen: Console.WriteLine(namen[0]); - Seite 131 - .NET-Framework & C#.NET Zweidimensionales Array Bezeichner des Arrays: umsaetze Zuweisung: umsaetze[0,0]=10000; Lesen: Console.WriteLine(umsaetze[0;0]); Array im Debugger Mehrdimensionale Arrays Grundsätzlich können auch Arrays mit mehr als zwei Dimensionen implementiert werden. Schwierigkeiten entstehen jedoch sehr häufig bei der Interpretation dieser Dimensionen. Von daher treten mehrdimensionale Arrays in der Praxis sehr selten auf. - Seite 132 - .NET-Framework & C#.NET 7.2 Eindimensionales Array Deklaration Nachstehend die allgemeine Schreibweise für die Deklaration eines eindimensionalen Arrays type[ ] identifier = new type[size] sowie Beispiele für ein alphanumerisches ein numerisches Array string[ ] namen = new string[5] double[ ] zahlen = new double[11] Merke: Im Gegensatz zur Deklaration einer einfachen Variablen folgen hier hinter dem Typ die eckigen Klammern - z.B. double[ ]. Danach folgt wie üblich der Bezeichner - in diesem Fall zahlen. Mittels des Schlüsselwortes new wird dann der Konstruktor aufgerufen und ein Interger-Wert für die Anzahl der Speicherplätze übergeben - hier new double[11]. Wichtig ist, dass dieser Wert die Anzahl der Speicherplätze darstellt. Er ist zu unterscheiden vom Index. Zu untercheiden sind: Index Speicherplätze Speichern von Werten Das Speichern und Lesen von Variablen erfolgt im Grundsatz wie bisher. Allerdings muss im Zusammenhang mit dem Bezeichner immer der Index angegeben werden, da sonst nicht eindeutig geklärt ist, welche Speicherstelle angesprochen werden soll. namen[0] = Console.ReadLine(); zahlen[0] = Convert.ToDouble(Console.ReadLine()); Lesen von Werten Console.WriteLine(namen[0]); Console.WriteLine(zahlen[0]); Zugriff mittels Variablen Der Index muss nicht in Form einer konkreten Zahl sondern kann auch als Variable angegeben werden. Dieses macht die Programmierung deutlich flexibler. for(zeile = 1; zeile <= 5; zeile++) Console.WriteLine(namen[zeile]); - Seite 133 - .NET-Framework & C#.NET 7.2.1 Eindimensionales alphanumerisches Array Problemstellung Bei dieser Anwendung sind nur fünf Namen einzugeben und diese danach wieder auf den Bildschirm auszugeben. Beim Testen des Programmes setzen Sie bitte einen Breakpoint bei der for-Schleife (Zeile 10) zum Einlesen der Daten. Durchlaufen Sie ab dort das Programm mittels der <F11>-Taste und verfolgen Sie die Zuweisung der eingegebenen Daten ins Array. Screenshot NSD (Nassi-Shneiderman-Diagramm/Struktogramm) - Seite 134 - .NET-Framework & C#.NET Code //Deklarationen int z; string[] namen = new string[5]; //Eingabe Console.WriteLine("NamensVerwaltung"); Console.WriteLine("****************"); Console.WriteLine(); for (z = 0; z <= 4; z++) { Console.Write("{0,2}. Name : ", z + 1); namen[z] = Console.ReadLine(); } //Ausgabe Console.WriteLine(); Console.WriteLine("NamensListe"); for (z = 0; z <= 4; z++) Console.WriteLine("{0,2}. Name : {1,10}", z+1, namen[z]); Console.ReadLine(); - Seite 135 - .NET-Framework & C#.NET 7.2.2 Eindimensionales numerisches Array Problemstellung Dieses Beispiel unterscheidet sich von dem vorherigen nur dadurch dass das Array nicht vom Typ string sondern vom Typ double ist. Dieses Beispiel wird in dem etwas später folgenden Kapitel zum Rechnen im Array wieder aufgegriffen. Vorläufig sollen nur zehn Zahlen eingegeben werden. Verfolgen Sie mit Hilfe des Debuggers die Zuweisung der Zahlen Zellen des Arrays. Screenshot NSD - Seite 136 - .NET-Framework & C#.NET Code //Deklarationen int z; double[] zahlen = new double[11]; //Prozedur //Eingabe Console.WriteLine("Eingabe von Zahlen"); Console.WriteLine("******************"); Console.WriteLine(); for (z = 0; z <= 9; z++) { Console.Write("{0,2} Zahl : ", z + 1); zahlen[z] = Convert.ToDouble(Console.ReadLine()); } Console.ReadLine(); - Seite 137 - .NET-Framework & C#.NET 7.2.3 Eindimensionales, variables numerisches Array Problemstellung Die bereits bekannte Problemstellung wird in diesem Beispiel um einen weiteren Aspekt erweitert. Sehr häufig treten Problemstellungen auf, bei denen das Array flexibel, z.B. in Abhängigkeit von User-Eingaben dimensioniert werden muss. Screenshot NSD Damit muss folglich die Grenze bei den Schleifen variabel gestaltet werden. Betrachtet man hierzu einmal das Struktogramm des vorherigen Abschnittes, so ergeben sich zwei Probleme: Die Instanziierung des Arrays kann nicht bei der Codierung mit festen Werten erfolgen, da diese erst vom User eingegeben werden müssen. Das Abbruchkriterum mit "z <= 9" ist ebenfalls nur für eine Problemstellung mit 10 Zahlen geeignet und ist variabel zu gestalten. Aufgrund dieser Anforderungen ergibt sich dann das nachstehende Struktogramm. Wichtig ist, dass das Abbruchkriterium der Schleife "anzahl - 1" ist. Dieses ergibt sich aus dem 0-basierten Index des Arrays. Will man bspw. fünf Datensätze eingeben, so ist die Anzahl der Felder im Array 5, der Index läuft aber von 0 bis 4. D.h. der Index des letzten Feldes ist immer um 1 geringer als die absoulte Anzahl. Die Instanziierung des Arrays muss jetzt in zwei Schritten erfolgen. Im unterstehenden Code wird erst nur die Variable deklariert: double[ ] zahlen Nach der Eingabe der Anzahl erfolgt dann die Instanziierung durch zahlen = new double[anzahl] - Seite 138 - .NET-Framework & C#.NET Code //Deklarationen int zeile, anzahl; double[] zahlen; //Prozedur Console.WriteLine("Eingabe von Zahlen"); Console.WriteLine("******************"); Console.WriteLine(); //Anzahl der Werte Console.Write("Anzahl der Zahlen : "); anzahl=Convert.ToInt32(Console.ReadLine()); Console.WriteLine(); //Dimensionierung des Arrays zahlen = new double[anzahl]; //Eingabe for (zeile = 0; zeile <= anzahl‐1; zeile++) { Console.Write("{0,2} Zahl : ", zeile + 1); zahlen[zeile] = Convert.ToDouble(Console.ReadLine()); } - Seite 139 - .NET-Framework & C#.NET 7.3 Zweidimensionales Array Deklaration Nachstehend die allgemeine Schreibweise für die Deklaration eines zweidimensionalen Arrays type[,] identifier = new type[size, size] sowie Beispiele für ein alphanumerisches ein numerisches Array string[,] namen = new string[5, 4] double[,] zahlen = new double[10, 3] Bei der Deklaration ist wichtig, dass bei einem zweidimensionalen Array in den eckigen Klammern des Typs bereits ein Komma steht. Hierdurch wird festgelegt, dass das Array zwei Dimensionen besetzt. Beim Aufruf des Konstrukteurs müssen dann auch in eckigen Klammern zwei Integer-Werte übergeben werden. Speichern von Werten Beim Zugriff auf die Speicherplätze eines zweidimensionalen Arrays ist nur zu beachten, dass auch zwei Indices angegeben werden. namen[0, 0] = Console.ReadLine(); zahlen[0, 0] = Convert.ToDouble(Console.ReadLine()); Lesen von Werten Console.WriteLine(namen[0, 0]); Console.WriteLine(zahlen[0, 0]); Zugriff mittels Variablen Wie bereits bekannt, können auch beim zweidimensionalen Array Integer-Variablen als Indizien verwendet werden. for(zeile = 1; zeile <= 5; zeile++) for (spalte = ; spalte <= 4; spalte++) Console.WriteLine(namen[zeile, spalte]); - Seite 140 - .NET-Framework & C#.NET 7.3.1 Zweidimensionales numerisches Array Problemstellung Bei dieser Anwendung zum numerischen, zweidimensionalen Array sollen von drei Filialen die Umsatzzahlen eines ersten und eines zweiten Halbjahres einund dann in Tabellenform ausgegeben werden. Berechnungen sind hier noch nicht vorgesehen. Screenshot NSD - Seite 141 - .NET-Framework & C#.NET Code //Deklarationen double[,] umsaetze = new double[3, 2]; int z, s; //Prozedur //Eingabe Console.WriteLine("Filial‐Umsätze"); Console.WriteLine("**************"); Console.WriteLine(); for (z = 0; z <= 2; z++) for (s = 0; s <= 1; s++) { Console.Write("Filiale {0,2}, Halbjahr {1,2} : ", z + 1, s + 1); umsaetze[z, s] = Convert.ToDouble(Console.ReadLine()); } //Ausgabe Console.WriteLine(); Console.WriteLine("Umsatz‐Tabelle"); Console.WriteLine("**************"); Console.WriteLine(); Console.WriteLine("{0,10} {1,15} {2,15}", "Filiale", "1. Halbjahr", "2. Halbjahr"); Console.Write‐ Line("******************************************"); for (z = 0; z <= 2; z++) Console.WriteLine("Filiale {0,2} {1,15:N} {2,15:N}", z + 1, umsaetze[z, 0], umsaetze[z, 1]); Console.ReadLine(); - Seite 142 - .NET-Framework & C#.NET 7.3.2 Zweidimensionales, variables numerisches Array Problemstellung Bei dieser Anwendung zum numerischen, zweidimensionalen Array geht es erneut um eine variable Dimensionierung des Arrays. Der Anwender kann auch die Anzahl der gewünschten Filialen eingeben. Instanziierung des Array auf Basis der Benutzereingaben variable Steuerung der Eingabe variable Steuerung der Ausgabe Screenshot NSD - Seite 143 - .NET-Framework & C#.NET Code //Deklarationen double[,] umsaetze; int anzahl, z, s; //Prozedur //Eingabe Console.WriteLine("Filial‐Umsätze"); Console.WriteLine("**************"); Console.WriteLine(); //Aufbau Array Console.Write("Anzahl der Filialen : "); anzahl = Convert.ToInt16(Console.ReadLine()); umsaetze = new double[anzahl+1, 3]; //Eingabe for (z = 0; z <= anzahl‐1; z++) for (s = 0; s <= 1; s++) { Console.Write("Filiale {0,2}, Halbjahr {1,2} : ", z + 1, s + 1); umsaetze[z, s] = Convert.ToDouble(Console.ReadLine()); } //Ausgabe Console.WriteLine(); Console.WriteLine("Umsatz‐Tabelle"); Console.WriteLine("**************"); Console.WriteLine(); Console.WriteLine("{0,10} {1,15} {2,15}", "Filiale", "1. Halbjahr", "2. Halbjahr"); Console.WriteLine("‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐ ‐‐‐‐‐‐‐‐‐"); for (z = 0; z <= anzahl‐1; z++) Console.WriteLine("Filiale {0,2} {1,15:N} {2,15:N}", z + 1, umsaetze[z, 0], umsaetze[z, 1]); Console.ReadLine(); - Seite 144 - .NET-Framework & C#.NET 7.4 Rechnen im Array 7.4.1 Rechnen im eindimensionalen Array Aufbau des Arrays Anzahl der Speicherstellen: 11 Index: 0 bis 10 Summe in Speicherzelle 10 Prinzip der Addition 1. Schritt zahlen[10] = zahlen[10] + zahlen[0]; zahlen[10] = zahlen[10] + zahlen[1]; zahlen[10] = zahlen[10] + zahlen[2]; ... zahlen[10] = zahlen[10] + zahlen[9]; 2. Schritt for (zeile = 0; zeile <= 9; zeile++) zahlen[10] = zahlen[10] + zahlen[zeile] Dieser Algorithmus umfasst nur noch zwei Zeilen und ist unabhängig von der Anzahl der zu addierenden Werte. Es ist ausschließlich im Schleifenkopf das Abbruchkriterium auf einen beliebigen anderen Wert zu setzen. - Seite 145 - .NET-Framework & C#.NET NSD Code //Deklarationen int z; double[] zahlen = new double[11]; //Prozedur //Eingabe Console.WriteLine("Eingabe von Zahlen"); Console.WriteLine("******************"); Console.WriteLine(); for (z = 0; z <= 9; z++) { Console.Write("{0,2} Zahl : ", z + 1); zahlen[z] = Convert.ToDouble(Console.ReadLine()); } //Berechnung for (z = 0; z <= 9; z++) zahlen[10] = zahlen[10] + zahlen[z]; //Ausgabe Console.WriteLine(); Console.WriteLine("Summe : {0,5:N}", zahlen[10]); - Seite 146 - .NET-Framework & C#.NET 7.4.2 Rechnen im eindimensionalen, variablen Array Anzahl versus Index Bei den nachstehenden Erläuterungen gehen wir davon aus, dass die Anzahl der zu erfassenden Daten in der Variabel anzahl gespeichert wird. Der Inhalt der Variablen anzahl wird zum einen bei der Deklaration für die Anzahl der Speicherplätze benötigt. Hier wird der Inhalt dieser Variable als die physische Anzahl angesehen. Des Weiteren wird der Inhalt dieser Variablen häufig in Schleifen beim Zugriff auf die Speicherplätze verwendet. Hierbei wird sie jedoch als Index interpretiert, der immer null-basiert ist. Summation bei flexibler Anzahl Speichern der Summe im Array => Anzahl der Speicherplätze "anzahl+1". Index für die Werte: 0 bis "anzahl-1". Index für die Summe: "anzahl". - Seite 147 - .NET-Framework & C#.NET Deklaration im Code double[] zahlen; zahlen = new double[anzahl+1]; Screenshot NSD - Seite 148 - .NET-Framework & C#.NET Code //Deklarationen int zeile, anzahl; double[] zahlen; //Prozedur //Eingabe Console.WriteLine("Eingabe von Zahlen"); Console.WriteLine("******************"); Console.WriteLine(); //Anzahl der Werte Console.Write("Anzahl der Zahlen : "); anzahl=Convert.ToInt32(Console.ReadLine()); Console.WriteLine(); //Dimensionierung des Arrays zahlen = new double[anzahl+1]; //Eingabe for (zeile = 0; zeile <= anzahl‐1; zeile++) { Console.Write("{0,2} Zahl : ", zeile + 1); zahlen[zeile] = Convert.ToDouble(Console.ReadLine()); } //Berechnung for (zeile = 0; zeile <= anzahl‐1; zeile++) zahlen[anzahl] = zahlen[anzahl] + zahlen[zeile]; //Ausgabe Console.WriteLine(); Console.WriteLine("Summe : {0,5:N}", zahlen[anzahl]); Console.ReadLine(); - Seite 149 - .NET-Framework & C#.NET 7.4.3 Rechnen im zweidimensionalen Array Struktur des Arrays Berechnung des Jahresumsatzes die Filiale. Berechnung des gesamten Umsatzes über alle Filialen je Halbjahr. Berechnung des Gesamtumsatzes im Jahr. Berechnung der Spaltensummen Summation der 1. Spalte for (zeile = 0; zeile <= 2; zeile++) umsaetze[3] = umsaetze[3] + umsaetze[zeile] for (zeile = 0; zeile <= 2; zeile++) umsaetze[3,0] = umsaetze[3,0] + umsaetze[zeile,0] Summation der 2. Spalte for (zeile = 0; zeile <= 2; zeile++) umsaetze[3,1] = umsaetze[3,1] + umsaetze[zeile,1] Verallgemeinerung für beliebig viele Spalte for(spalte = 0; spalte <=1; spalte++) for (zeile = 0; zeile <= 2; zeile++) umsaetze[3,1] = umsaetze[3,1] + umsaetze[zeile,1] Berechnung der Zeilensummen Summation der 1. Zeile for(spalte = 0; spalte <= 1; spalte++) umsaetze[0,2]=umsaetze[0,2]+umsaetze[0,spalte]; Summation der 2. Zeile for(spalte = 0; spalte <= 1; spalte++) umsaetze[1,2]=umsaetze[1,2]+umsaetze[1,spalte]; Verallgemeinerung für beliebig viele Zeilen for(zeile = 0; zeile <= 3; zeile++) for(spalte = 0; spalte <= 1; spalte++) umsaetze[zeile,2]=umsaetze[zeile,2]+umsaetze[1,spalte]; - Seite 150 - .NET-Framework & C#.NET Screenshot NSD - Seite 151 - .NET-Framework & C#.NET Code //Deklarationen double[,] umsaetze = new double[4, 3]; int z, s; //Prozedur //Eingabe Console.WriteLine("Filial‐Umsätze"); Console.WriteLine("**************"); Console.WriteLine(); for (z = 0; z <= 2; z++) for (s = 0; s <= 1; s++) { Console.Write("Filiale {0,2}, Halbjahr {1,2} : ", z + 1, s + 1); umsaetze[z, s] = Convert.ToDouble(Console.ReadLine()); } //Zeilensummen for (z = 0; z <= 2; z++) for (s = 0; s <= 1; s++) umsaetze[z, 2] = umsaetze[z, 2] + umsaetze[z, s]; //Spaltensummen for (s = 0; s <= 2; s++) for (z = 0; z <= 2; z++) umsaetze[3, s] = umsaetze[3, s] + umsaetze[z, s]; - Seite 152 - .NET-Framework & C#.NET //Ausgabe Console.WriteLine(); Console.WriteLine("Umsatz‐Tabelle"); Console.WriteLine("**************"); Console.WriteLine(); Console.WriteLine("{0,10} {1,15} {2,15} {3,15}", "Filiale", "1. Halbjahr", "2. Halbjahr", "Summe"); Console.WriteLine("‐…"); for (z = 0; z <= 2; z++) Console.WriteLine("Filiale {0,2} {1,15:N} {2,15:N} {3,15:N}", z + 1, umsaetze[z, 0], umsaetze[z, 1], umsaetze[z, 2]); Console.WriteLine("‐…"); Console.WriteLine("Summe {0,15:N} {1,15:N} {2,15:N}", umsaetze[3, 0], umsaetze[3, 1], umsaetze[3, 2]); Console.WriteLine("=…"); Console.ReadLine(); - Seite 153 - .NET-Framework & C#.NET 7.4.4 Rechnen im zweidimensionalen, variablen Array Struktur des Arrays Schleifensteuerung am Beispiel der Eingabe-Schleife Screenshot - Seite 154 - .NET-Framework & C#.NET NSD - Seite 155 - .NET-Framework & C#.NET Code //Deklarationen double[,] umsaetze; int anzahl, z, s; //Prozedur //Eingabe Console.WriteLine("Filial‐Umsätze"); Console.WriteLine("**************"); Console.WriteLine(); //Aufbau Array Console.Write("Anzahl der Filialen : "); anzahl = Convert.ToInt16(Console.ReadLine()); umsaetze = new double[anzahl+1, 3]; //Eingabe for (z = 0; z <= anzahl‐1; z++) for (s = 0; s <= 1; s++) { Console.Write("Filiale {0,2}, Halbjahr {1,2} : ", z + 1, s + 1); umsaetze[z, s] = Convert.ToDouble(Console.ReadLine()); } //Zeilensummen for (z = 0; z <= anzahl‐1; z++) for (s = 0; s <= 1; s++) umsaetze[z, 2] = umsaetze[z, 2] + umsaetze[z, s]; - Seite 156 - .NET-Framework & C#.NET //Spaltensummen for (s = 0; s <= 2; s++) for (z = 0; z <= anzahl‐1; z++) umsaetze[anzahl, s] = umsaetze[anzahl, s] + umsaetze[z, s]; //Ausgabe Console.WriteLine(); Console.WriteLine("Umsatz‐Tabelle"); Console.WriteLine("**************"); Console.WriteLine(); Console.WriteLine("{0,10} {1,15} {2,15} {3,15}", "Filiale", "1. Halbjahr", "2. Halbjahr", "Summe"); Console.WriteLine("‐…"); for (z = 0; z <= anzahl‐1; z++) Console.WriteLine("Filiale {0,2} {1,15:N} {2,15:N} {3,15:N}", z + 1, umsaetze[z, 0], umsaetze[z, 1], umsaetze[z, 2]); Console.WriteLine("‐…"); Console.WriteLine("Summe {0,15:N} {1,15:N} {2,15:N}", umsaetze[anzahl, 0], umsaetze[anzahl, 1], umsaetze[anzahl, 2]); Console.WriteLine("=…"); Console.ReadLine(); - Seite 157 - .NET-Framework & C#.NET 7.5 Übungen 7.5.1 Gewinn-Ermittlung (Array fix) Bei dem folgenden Programm soll für vier Produkte der Einkaufs- und der Verkaufspreis eingegeben werden. Die Eingaben werden in einem Array erfasst. Bei den Berechnungen wird der Gewinn absolut als Differenz zwischen EK und VK und prozentual zum EK innerhalb des Array ermittelt und gespeichert. Des Weiteren soll von den ersten drei Spalten die Summe berechnet werden. Der nachstehende ScreenShot veranschaulicht die Berechnungen. Screenshot - Seite 158 - .NET-Framework & C#.NET NSD - Seite 159 - .NET-Framework & C#.NET Code //Deklarationen double[,] gewinn = new double[5, 4]; int z, s; //Prozedur //Eingabe Console.WriteLine("Eingabe von Einkaufspreis und Verkaufspreis"); Console.WriteLine("*…"); Console.WriteLine(); for (z = 0; z <= 3; z++) { Console.Write("EK Produkt {0,2}: ", z + 1); gewinn[z, 0] = Convert.ToDouble(Console.ReadLine()); Console.Write("VK Produkt {0,2}: ", z + 1); gewinn[z, 1] = Convert.ToDouble(Console.ReadLine()); } //Berechnungen Gewinn (absolut & prozentual) for (z = 0; z <= 3; z++) { gewinn[z, 2] = gewinn[z, 1] ‐ gewinn[z, 0]; gewinn[z, 3] = gewinn[z, 2] / gewinn[z, 0] * 100; } - Seite 160 - .NET-Framework & C#.NET //Berechnung Spaltensummen for (s = 0; s <= 2; s++) { for (z = 0; z <= 3; z++) { gewinn[4, s] = gewinn[4, s] + gewinn[z, s]; } } //Ausgabe Console.WriteLine(); Console.WriteLine("Liste überr alle Produkte"); Console.WriteLine("*************************"); Console.WriteLine(); Console.WriteLine("Produkt EK VK Gewinn(abs) Gewinn(%) "); Console.WriteLine("*…"); for (z = 0; z <= 3; z++) { Console.WriteLine("Produkt {0,2} {1,10:N} {2,10:N} {3,10:N} {4,10:N}", z + 1, gewinn[z, 0], gewinn[z, 1], gewinn[z, 2], gewinn[z, 3]); } Console.WriteLine("‐…"); Console.WriteLine("Summe {0,10:N} {1,10:N} {2,10:N} {3,10:N}", gewinn[4, 0], gewinn[4, 1], gewinn[4, 2], gewinn[4, 3]); Console.WriteLine("=…"); - Seite 161 - .NET-Framework & C#.NET 7.5.2 Gewinn-Ermittlung (Array variabel) Bei dem nachstehenden Beispiel wurde die Problemstellung insofern geändert, dass die Anzahl der Produkte flexibel ist. Diese wird als erstes erfasst. Danach wird das Array dimensioniert. Die Schleifen bei der Eingabe, den Berechnungen und der Ausgabe sind entsprechend variabel zu programmieren. Im Wesentlich handelt es sich dabei um eine variable Obergrenze bei den Schleifen. Screenshot - Seite 162 - .NET-Framework & C#.NET NSD - Seite 163 - .NET-Framework & C#.NET Code //Deklarationen double[,] gewinn; int z, s, anzahl; //Prozedur //Eingabe Console.WriteLine("Eingabe von Einkaufspreis und Verkaufspreis"); Console.WriteLine("*******************************************"); Console.WriteLine(); //Bestimmung des Arrays Console.Write("Anzahl der Produkte : "); anzahl = Convert.ToInt16(Console.ReadLine()); gewinn = new Double[anzahl + 1, 4]; for (z = 0; z <= anzahl ‐ 1; z++) { Console.Write("EK Produkt {0,2}: ", z + 1); gewinn[z, 0] = Convert.ToDouble(Console.ReadLine()); Console.Write("VK Produkt {0,2}: ", z + 1); gewinn[z, 1] = Convert.ToDouble(Console.ReadLine()); } //Berechnungen Gewinn (absolut & prozentual for (z = 0; z <= anzahl ‐ 1; z++) { gewinn[z, 2] = gewinn[z, 1] ‐ gewinn[z, 0]; gewinn[z, 3] = gewinn[z, 2] / gewinn[z, 0] * 100; - Seite 164 - .NET-Framework & C#.NET } //Berechnung Spaltensummen for (s = 0; s <= 2; s++) { for (z = 0; z <= anzahl ‐ 1; z++) { gewinn[anzahl, s] = gewinn[anzahl, s] + gewinn[z, s]; } } //Ausgabe Console.WriteLine(); Console.WriteLine("Liste überr alle Produkte"); Console.WriteLine("*************************"); Console.WriteLine(); Console.WriteLine("Produkt EK VK Gewinn(abs) Gewinn(%) "); Console.WriteLine("**************************************************************"); for (z = 0; z <= anzahl ‐ 1; z++) { Console.WriteLine("Produkt {0,2} {1,10:N} {2,10:N} {3,10:N} {4,10:N}", z + 1, gewinn[z, 0], gewinn[z, 1], gewinn[z, 2], gewinn[z, 3]); } Console.WriteLine("‐…"); Console.WriteLine("Summe {0,10:N} {1,10:N} {2,10:N} {3,10:N}", gewinn[anzahl, 0], gewinn[anzahl, 1], gewinn[anzahl, 2], gewinn[anzahl, 3]); Console.WriteLine("=…"); - Seite 165 - .NET-Framework & C#.NET C. Klassen der FCL & Windowsanwendungen Wie bereits mehrfach angesprochen, behandeln wir in diesem Modul zwei grundlegende Bereiche: zum einen die Programmiersprache C# und zum anderen die Klassen der FCL. Im dritten Teil des Skripts befassen wir uns nun mit Teilen der FCL. Die FCL selbst beinhaltet eine Vielzahl von Klassen.Diese beinhalten dann wiederum Methoden(), Ereignisse und Eigenschaften. So kennt beispielsweise die Klasse Convert die Methode ToDouble(), mit deren Hilfe z.B. ein String in eine Zahl vom Type double konvertiert werden kann. 8 .NET-Entwicklungsumgebung - Teil 2 In diesem Kapitel wird die .NET-Entwicklungsumgebung noch einmal im Gesamtzusammenhang erläutert. Bereits in Kapitel 3 (Teil A des Skripts) wurde auf die .NET-Entwicklung eingegangen. Führen Sie sich bitte die wichtigsten Inhalte hieraus nochmal zu Gemüte. In diesem Kapitel wird das Wissen über die .NET IDE vertieft. Hier noch einmal ein Reminder auf Kapitel 3: Die .NET-Welt besteht - wie bereits mehrfach erläutert - aus den beiden Komponenten: .NET-Framework (Rahmenstruktur, welche Klassen usw. bereitstellt) Entwicklungsumgebung Visual Studio (hier programmieren wir) Mit der FCL (Klassenbibliothek) als dem wesentlichen Bestandteil des .NETFrameworks haben wir uns in den vorherigen Kapiteln schon ausführlich beschäftigt. Jetzt steht die IDE - die Entwicklungsumgebung in Visual Studio - im Fokus. Im Gegensatz zur Umgebung Visual Studio .NET ist C# unsere Programmiersprache! Sie funktioniert auch unabhängig von Viusal Studio in alternativen Entwicklungsumgebungen. Ggf. kann das auch ein vollkommen unkomfortabler Editor sein. Der Quellcode muss nur mittels des .NET-Compilers übersetzt werden. - Seite 166 - .NET-Framework & C#.NET 8.1 Ansicht der IDE Designer-Ansicht Code-Ansicht - Seite 167 - .NET-Framework & C#.NET Umschalten zwischen den Ansichten Tastenkombinationen Code-Ansicht: F7 Designer-Ansicht: Umschalt + F7 Umschalten über das Menü Bestandteile und Fenster einer Windows-Anwendung Diese Datei enthält den C#-Code, den der Entwickler für die Form programmiert. Unter diesem Register wird der Designer zum Entwurf der Form1.cs Form aktiviert. Da diese graphischen Elemente in Code [Entwurf] umgesetzt werden, gibt es keine entsprechende Datei im Explorer. Hier wird der auf Basis des Design-Entwurfs der von der Form1.Desig- IDE generierte Code abgelegt. D.h. alle Aktionen die beim ner.cs Entwurf per Drag & Drop durchgeführt werden, werden vom Generator in entsprechenden Code umgesetzt. Dieser Programmteil enthält mit der Main-Methode den Program.cs Start des C#-Programms. Form1.cs - Seite 168 - .NET-Framework & C#.NET 8.2 Rückblick: Beispiel für Windows-Anwendung Was ist eine Windows-Anwendung? Aufbau einer Form in der Designer-Ansicht Eigenschaften - Seite 169 - .NET-Framework & C#.NET Ereignisbasierte Methoden in der Code-Ansicht Methodenrumpf für ereignisbasierte Methode erzeugen Code für Ereignis-Methode - Seite 170 - .NET-Framework & C#.NET 8.3 Rückblick: Anatomie von Windows-Anwendungen Ablauflogik beim Aufruf - Seite 171 - .NET-Framework & C#.NET Form1.Designer.cs - Seite 172 - .NET-Framework & C#.NET Form1.cs Program.cs - Seite 173 - .NET-Framework & C#.NET 9 Objektorientierte Programmierung - Theorie Teil 2 - Seite 174 - .NET-Framework & C#.NET 9.1 Klassen & Klassenmember Struktur Namespace eigenen Anwendungen FCL Mitglieder eines Namespace (Namespace-Member) Klassen Zugriffsmodifizierer Mitglieder von Klassen (Class-Member) Konstruktor Methoden Ereignisse (Events) Felder Eigenschaften (Properties) Abgrenzung Eigenschaften & Felder Differenzierung von Methoden Überladene Methoden Statische Methoden - Seite 175 - .NET-Framework & C#.NET 9.2 Vererbung & Instanziierung Vererbung Übertragung der Struktur (Eigneschaften, Methoden, Ereignisse …) einer Klasse auf eine neue Klasse Klassenhierarchie Instanziierung Klasse => Objekt Wirkungsweise von Vererbung & Instanziierung - Seite 176 - .NET-Framework & C#.NET 9.3 Vererbung bei Windows-Anwendungen Grundidee Zentrale Frage: Wie und wo wird das im Code realisiert? Die Form-Klasse der FCL bildet die Basis-Klasse für die neue Klasse; sie enthält somit die Grundinformationen/Eigenschaften (Member) Die abgeleitete Klasse ist die neu zu erstellende Form, die einige weitere Elemente wie den Button und das Label enthält. Entscheidend ist die folgende Anweisung: public partial class Form1 : Form Vernachlässigt man vorerst die Modifizierer public partialso bleibt als Kern die folgende Anweisung übrig, durch die die Vererbung realisiert wird: class Form1 : Form Beispiel Button-Klasse class myButton : Button - Seite 177 - .NET-Framework & C#.NET 9.4 Instanziierung bei Windows-Anwendungen Instanziierung im Designer Instanziierung im Code Der generierte Code in der Designer.cs this.btnStart.Location = new System.Drawing.Point(187, 12); this.btnStart.Name = "btnStart"; this.btnStart.Size = new System.Drawing.Size(75, 23); this.btnStart.TabIndex = 0; this.btnStart.Text = "Start"; this.btnStart.UseVisualStyleBackColor = true; this.btnStart.Click += new System.EventHandler(this.btnStart_Click); Instanziierung this.button1 = new System.Windows.Forms.Button(); Festlegung der Eigenschaften (im Eigenschaftenfenster oder im Designer geändert) this.button1.Name = "button1"; this.button1.Text = "Ausgabe"; - Seite 178 - .NET-Framework & C#.NET 9.5 Klassen der FCL & Klassenmember Aktivierung des Objekts Eigenschaften Änderung von Eigenschaften in der IDE Änderung von Eigenschaften durch Code label1.Text = "Hello World"; Methoden Console.WriteLine(); Console.ReadLine(); lblAusgabe.Hide(); - Seite 179 - .NET-Framework & C#.NET Ereignisse Aktivieren der Ereignisansicht: Konstruktor this.btnStart = new System.Windows.Forms.Button(); - Seite 180 - .NET-Framework & C#.NET 9.6 Eigenen Klassen & Klassenmember Idee public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void btnStart_Click (object sender, EventArgs e) { lblAusgabe.Text = "Hello World !"; } private void btnEnde_Click (object sender, EventArgs e) { this.Close(); } Ereignisse & Methoden Unterscheidung der beiden Begriffe „Ereignis“ und „Methode“. Struktur einer ereignisorientierten Methode Diese Methode wird beim Auftreten des Click-Ereignis bei dem Objekt Button btnStart ausgeführt. Der Bezeichner der Methode btnStart_Click Bezeichner des Ereignisses & Bezeichner des Objekts Zugriffsmodifizierer private Im Moment soll hierzu nur erläutert werden, dass diese Methode damit nur innerhalb eines bestimmten Bereiches verwendet werden kann. Parameter der Methode: Input-Parameter: object sender und System.EventArgs e Output-Parameter: kein Parameter daher void - Seite 181 - .NET-Framework & C#.NET Einbindung einer ereignisorientierten Methode Desinger.cs this.btnStart.Click += new System.EventHandler(this.btnStart_Click); Merke Es darf daher auf keinen Fall der obige Methoden-Kopf manuell aufgebaut werden. Es würde damit die Anbindung an das entsprechende Event fehlen. Man darf daher auch nicht einen versehentlich erzeugten Methoden-Kopf einfach löschen. Damit würde das Event-Handling auf eine nicht existierende Methode verweisen und einen Fehler erzeugen. Hat man versehentlich einen Methoden-Kopf erzeugt, so muss man nicht nur diesen sondern auch das entsprechende Eventhandling in der Designer.cs löschen. Standard-Event Doppleklicken auf Objekt in der IDE erzeugt einen Methodenkopf für das Standard-Event Bei anderen Event sist der Weg über die Ereignis-Ansicht des Eigenschaften-Fensters notwendig. C#-Anweisungen einer ereignisorientierten Methode Objekteigenschaften dynamisch ändern lblAusgabe.Text = "Hello World !"; Objektmethoden im Code verwenden private void btnEin_Click(object Sender, EventArgs e) { lblAusgabe.Show(); } - Seite 182 - .NET-Framework & C#.NET 10 Namespace System.Windows.Forms In diesem Kapitel werden die zentralen Klassen des Namespace System.Windows.Forms dargestellt. In diesem Namespace sind alle für die Entwicklung von Windows-Oberflächen notwendigen Klassen - wie z.B. der LabelKlasse, der Button-Klasse usw. - zusammengefasst. 10.1 Strukturen des Namespace System.Windows.Forms Einordnung des Namespac Windows.System.Forms Die Klassen, die direkt auf einer Form instanziiert werden, werden als Steuerelemente – auch Controls – bezeichnet. Die am häufigsten verwendeten Klassen dieses Namespace befinden sich auch in der Toolbar. Toolbar - Steuerelemente in der VS-Entwicklungsumgebung - Seite 183 - .NET-Framework & C#.NET Erweiterung der Toolbar Die Toolbar kann jeder Entwickler den eigenen Bedürfnissen anpassen. Durch Klicken der rechten Maustaste auf der Toolbar gelangt man in das nachstehende Kontextmenü. - Seite 184 - .NET-Framework & C#.NET Struktur der Dokumentation - Seite 185 - .NET-Framework & C#.NET 10.2 Überblick Grundsätzlich ist es schwierig alle Klassen dieses Namespaces systematisch zu differenzieren. Wenn dieses komplett gelänge, könnte man anhand dieser Liste ausgehend von einer Problemstellung die möglichen Gestaltungsoptionen ablesen. Die bei den nachstehenden Listen stellen in Ansätzen eine solche Hilfe dar. Die erste Liste, die Kategorien, ist der Online-Dokumentation entnommen. Diese Liste beschreibt die Kategorien der Klassen. Die zweite Liste, in der Klassen nach Funktionsbereichen differenziert sind, kommt der oben geschilderten Hilfestruktur schon relativ nahe. In der ersten Spalte ist die Funktion, das heißt die Problemstellung, beschrieben. In der zweiten Spalte stehen die hierfür verwendbaren Steuerelemente. In der dritten Spalte folgt eine kurze Beschreibung dieser Steuerelemente. Kategorien Klassenkategorie Details Steuerelement, Benutzersteuerelement und Formular Die meisten Klassen im System.Windows.Forms-Namespace sind von der Control-Klasse abgeleitet. Die Control-Klasse stellt die Basisfunktionen für alle in einem Form angezeigten Steuerelemente zur Verfügung. Die Form-Klasse stellt ein Fenster in einer Anwendung dar. Hierzu gehören Dialogfelder, nicht modale Fenster sowie übergeordnete und untergeordnete MDI-Fenster (Multiple Document Interface). Sie können auch eigene Steuerelemente erstellen, indem Sie von der UserControl-Klasse ableiten. Menüs und Symbolleisten Windows Forms enthalten eine umfangreiche Auswahl an Klassen zum Erstellen benutzerdefinierter Symbolleisten und zeitgemäß gestalteter Menüs. ToolStrip, MenuStrip, ContextMenuStrip und StatusStrip können zum Erstellen von Symbolleisten, Menüleisten, Kontextmenüs und Statusleisten verwendet werden. Steuerelemente Der System.Windows.Forms-Namespace stellt verschiedene Steuerelementklassen bereit, mit denen Sie umfangreiche Benutzeroberflächen erstellen können. Einige Steuerelemente sind für die Dateneingabe in der Anwendung vorgesehen, z. B. das TextBox-Steuerelement und das ComboBox-Steuerelement. Andere Steuerelemente zeigen Anwendungsdaten an, z. B. das Label-Steuerelement und das ListView-Steuerelement. Der Namespace stellt außerdem Steuerelemente für das Aufrufen von Befehlen in der Anwendung bereit, z. B. das Button-Steuerelement. Mit dem WebBrowser-Steuerelement und verwalteten HTML-Klassen wie HtmlDocument können HTML-Seiten in Windows Forms-Anwendungen angezeigt und geändert werden. Das MaskedTextBox-Steuerelement ist ein erweitertes Steuerelement zur Dateneingabe, mit dem Masken für das automatische Annehmen oder Ablehnen von Benutzereingaben definiert werden können. Darüber hinaus kann das PropertyGrid-Steuerelement zum Erstellen eines eigenen Windows Forms-Designers verwendet werden, der die zur Entwurfszeit sichtbaren Eigenschaften der Steuerelemente anzeigt. - Seite 186 - .NET-Framework & C#.NET Layout Daten und Daten- Windows Forms definiert eine umfangreiche Architektur zum Binden an Datenquellen wie Datenbanken und XML-Dateien. Das DataGridView-Steuebindungen relement stellt eine benutzerdefinierbare Tabelle für das Anzeigen von Daten bereit, deren Zellen, Zeilen, Spalten und Ränder angepasst werden können. Das BindingNavigator-Steuerelement stellt eine standardisierte Methode zur Navigation und Arbeit mit Daten in einem Formular dar. BindingNavigator wird häufig zusammen mit dem BindingSource-Steuerelement zur Navigation und Interaktion mit den Datensätzen in einem Formular verwendet. Das Layout von Steuerelementen in einem Anzeigebereich, z. B. eines Formular oder eines Steuerelements, kann in Windows Forms mithilfe verschiedener wichtiger Klassen gestaltet werden. FlowLayoutPanel bestimmt das Layout aller darin enthalten Steuerelemente der Reihe nach, und mit TableLayoutPanel können Sie Zellen und Zeilen für das Layout von Steuerelementen in einem festen Raster festlegen. SplitContainer teilt die Anzeigefläche in zwei oder mehr anpassbare Teile. - Seite 187 - .NET-Framework & C#.NET Funktionsbereiche Funktion Textbearbeitung Steuerelement TextBox RichTextBox Textanzeige (schreibgeschützt) Label LinkLabel StatusBar Auswahl aus einer Liste CheckedListBox ComboBox ListBox ListView NumericUpDown TreeView Grafikanzeige PictureBox Speichern von Grafiken ImageList Festlegen von Werten CheckBox CheckedListBox RadioButton Trackbar Datumseinstellung DateTimePicker MonthCalendar Dialogfelder ColorDialog FontDialog OpenFileDialog Beschreibung Zeigt zur Entwurfszeit eingegebenen Text an, der zur Laufzeit von den Benutzern bearbeitet oder programmgesteuert geändert werden kann. Text kann im Nur-Text- oder im Rich-Text-Format (RTF) angezeigt werden. Zeigt Text an, den Benutzer nicht direkt bearbeiten können. Zeigt Text als Hyperlink an und löst ein Ereignis aus, wenn die Benutzer auf den Text klicken. In der Regel stellt der Text eine Verknüpfung zu einem anderen Fenster oder einer Website dar. Zeigt Informationen über den aktuellen Zustand der Anwendung in einem Rahmenfenster an, i. d. R. am unteren Rand eines übergeordneten Formulars. Zeigt eine bildlauffähige Liste von Elementen an, neben denen jeweils ein Kontrollkästchen steht. Zeigt eine Dropdownliste von Elementen an. Zeigt eine Liste von Text- und Grafikelementen (Symbolen) an. Zeigt Elemente in einer von vier verschiedenen Ansichten an: Diese Ansichten umfassen nur Text, Text mit kleinen Symbolen, Text mit großen Symbolen und eine Detailansicht. Zeigt eine Liste von Nummernzeichen an, in der Benutzer mit den Schaltflächen Nach oben bzw. Nach unten einen Bildlauf durchführen können. Zeigt eine hierarchische Auflistung von Knotenobjekten an, die aus Text mit optionalen Kontrollkästchen oder Symbolen bestehen können. Zeigt Grafikdateien, z. B. Bitmaps und Symbole, in einem Rahmen an. Dieses Steuerelement dient als Repository für Bilder. ImageList-Steuerelemente und die darin enthaltenen Bilder können in nachfolgenden Anwendungen erneut verwendet werden. Zeigt ein Kontrollkästchen und eine Textbezeichnung an. In der Regel wird dieses Steuerelement zum Einstellen von Optionen verwendet. Zeigt eine bildlauffähige Liste von Elementen an, neben denen jeweils ein Kontrollkästchen steht. Zeigt eine Schaltfläche an, die aktiviert oder deaktiviert werden kann. Benutzer können auf einer Skala mit einem Ziehpunkt Werte einstellen. Zeigt einen grafischen Kalender an, in dem Benutzer ein Datum oder eine Uhrzeit auswählen können. Zeigt einen grafischen Kalender an, in dem Benutzer einen Datumsbereich auswählen können. Zeigt das Dialogfeld zur Farbauswahl an, in dem Benutzer die Farbe eines Oberflächenelements einstellen können. Zeigt ein Dialogfeld an, in dem Benutzer eine Schriftart und deren Attribute einstellen können. Zeigt ein Dialogfeld an, in dem Benutzer zu einer Datei navigieren und diese auswählen können. - Seite 188 - .NET-Framework & C#.NET PrintDialog PrintPreviewDialog SaveFileDialog Menüsteuerelemente MainMenu ContextMenu Befehle Button LinkLabel ToolBar Gruppierung weiterer Steuerelemente Panel GroupBox TabControl Zeigt ein Dialogfeld an, in dem Benutzer einen Drucker auswählen und dessen Attribute einstellen können. Zeigt ein Dialogfeld mit der Druckvorschau eines PrintDocument-Objekts an. Zeigt ein Dialogfeld an, in dem Benutzer eine Datei speichern können. Stellt eine Oberfläche zum Erstellen von Menüs zur Entwurfszeit bereit. Implementiert ein Kontextmenü, das angezeigt wird, wenn die Benutzer mit der rechten Maustaste auf ein Objekt klicken. Mit diesem Steuerelement kann ein Vorgang gestartet, angehalten oder unterbrochen werden. Zeigt Text als Hyperlink an und löst ein Ereignis aus, wenn die Benutzer auf den Text klicken. In der Regel stellt der Text eine Verknüpfung zu einem anderen Fenster oder einer Website dar. In diesem Steuerelement ist eine Auflistung von Schaltflächen-Steuerelementen enthalten. Gruppiert einen Satz von Steuerelementen auf einem bildlauffähigen Rahmen ohne Bezeichnung. Gruppiert einen Satz von Steuerelementen (z. B. Optionsfelder) auf einem nicht bildlauffähigen Rahmen mit Bezeichnung. Stellt eine Seite mit Registerkarten zum effizienten Organisieren von und Zugreifen auf gruppierte(n) Objekte(n) bereit. - Seite 189 - .NET-Framework & C#.NET 10.3 Elementare Steuerelemente (Klassen) In diesem Kapitel werden die wichtigsten Klassen für den Aufbau einer Windows-Form erläutert. Als erstes wird das die Button-Klasse sein, die bereits aus dem Eingangsbeispiel bekannt ist. Der Button ist das zentrale Control, um ereignisorientierte Methoden zu implementieren. Einfache Ausgaben auf einer Form werden in der Regel über Label – Klasse realisiert. Die Erfassung von Eingaben erfolgt über die Textbox-Klasse. Zu einem späteren Zeitpunkt werden weitere Ein-und Ausgabe-Controls erläutert. - Seite 190 - .NET-Framework & C#.NET 10.3.1 Button-Klasse Der ist eines der wichtigsten Controls, das Ereignis-Prozeduren auslöst. Es wird sehr häufig zur Ablaufsteuerung von Applikationen verwendet. Eigenschaften Eigenschaft BackColor BackgroundImage DialogResult Height TabIndex Text TextAlign Visible Width Beschreibung Ruft die Hintergrundfarbe für das Steuerelement ab oder legt diese fest. Ruft das im Steuerelement angezeigte Hintergrundbild ab oder legt dieses fest. Ruft einen Wert ab, der beim Klicken auf die Schaltfläche an das übergeordnete Formular zurückgegeben wird, oder legt diesen fest. Ruft die Höhe des Steuerelements ab oder legt diese fest. Ruft die Aktivierreihenfolge des Steuerelements in dessen Container ab oder legt diese fest. Ruft den diesem Steuerelement zugeordneten Text ab oder legt diesen fest. Die Texteigenschaft dient der Beschriftung des Button, die allerdings meistens nur im Entwicklungsmodus bei der Oberflächengestaltung gesetzt wird. Ruft die Ausrichtung des Textes auf dem Schaltflächen-Steuerelement ab oder legt diese fest. Ruft einen Wert ab, der angibt, ob das Steuerelement angezeigt wird, oder legt diesen fest. Ruft die Breite des Steuerelements ab oder legt diese fest. Ereignisse Ereignis Beschreibung Tritt beim Klicken auf das Steuerelement ein. Das Click-Ereignis ist das am meisten verwendete Ereignis für das AuslöClick-Ereignis sen einer Prozedur. Es bedeutet, dass die an den Button gebundene Prozedur beim Auftreten des Click- Ereignisses beim Button ausgeführt wird. Der Prozedur-Bezeichner setzt sich daher auch aus dem Namen des Objektes und dem Ereignis zusammen. Beispiel private void btnAusgabe_Click(object sender, EventArgs e) { lblAusgabe.Text = "Hello World"; } - Seite 191 - .NET-Framework & C#.NET 10.3.2 Label-Klasse Das dient der Ausgabe von Texten und Zahlen. Die folgenden Member sind von zentraler Bedeutung: Eigenschaften Eigenschaft Anchor BackColor BorderStyle ForeColor Height Text TextAlign Visible Width Beschreibung Ruft ab oder legt fest, welche Ränder des Steuerelements an den Rändern des zugehörigen Containers verankert sind. Ruft die Hintergrundfarbe für das Steuerelement ab oder legt diese fest. Ruft die Rahmenart des Steuerelements ab oder legt diese fest. Ruft die Vordergrundfarbe des Steuerelements ab oder legt diese fest. Ruft die Höhe des Steuerelements ab oder legt diese fest. Ruft den diesem Steuerelement zugeordneten Text ab oder legt diesen fest. Diese Eigenschaft dient der Darstellung von Zahlen und Text auf dem Label-Objekt. Zu beachten ist, dass diese Eigenschaft vom Typ String ist und somit bei der Compiler-Einstellung Option Explicit On (eindeutige Deklaration ein) bei numerischen Werten eine Typkonvertierung vorgenommen werden muss. Ruft die Textausrichtung im Label ab oder legt diese fest. Ruft einen Wert ab, der angibt, ob das Steuerelement angezeigt wird, oder legt diesen fest. Ruft die Breite des Steuerelements ab oder legt diese fest. Beispiel private void btnAusgabe_Click_1(object sender, EventArgs e) { lblAusgabe.Text = "Hello World"; } - Seite 192 - .NET-Framework & C#.NET 10.3.3 TextBox-Klasse Die dient zur Eingabe von Zahlen und Texten. Die TextboxKlasse ist aber nicht sehr komfortabel, was die Überprüfung von Eingaben durch Eingabeformate betrifft. Will man hier mehr Komfort, sollte man sich der RichTextbox-Klasse bedienen. Eigenschaften Eigenschaft MaxLength Multiline ReadOnly ScrollBars SelectedText Text TextLength Beschreibung Ruft die maximale Anzahl an Zeichen ab, die Benutzer in das Textfeld-Steuerelement eingeben oder einfügen können, oder legt diese fest. Ruft einen Wert ab, der angibt, ob dies ein mehrzeiliges Textfeld-Steuerelement ist, oder legt diesen fest. Ruft einen Wert ab, der angibt, ob der im Textfeld enthaltene Text schreibgeschützt ist, oder legt diesen fest. Ruft die in einem mehrzeiligen TextBox-Steuerelement anzuzeigenden Bildlaufleisten ab oder legt diese fest. Ruft einen Wert ab, der den derzeitig markierten Text im Steuerelement angibt, oder legt diesen fest. Überschrieben. Diese Eigenschaft speichert die eingegebenen Zahlen und Text. Zu beachten ist, dass diese Eigenschaft vom Typ String ist und somit bei der Compiler-Einstellung Option Explicit On (eindeutige Deklaration ein) bei numerischen Werten eine Typkonvertierung vorgenommen werden muss. Ruft die Länge des Textes im Steuerelement ab. Methoden() Eigenschaft AppendText Clear Beschreibung Fügt Text an den aktuellen Text des Textfeldes an. Löscht den gesamten Text aus dem Textfeld-Steuerelement. Mit der Clear-Methode wird die Text-Eigenschaft der TextBox gelöscht. - Seite 193 - .NET-Framework & C#.NET 10.4 Übungen - Elementares Kommen wir nun zum ersten Teil der Übungen zum Namensraum System.Windows.Forms. 10.4.1 Division zweier Zahlen Programmbeschreibung Der nachstehend abgebildete Screenshot zeigt ein Programm zur Division zweier Zahlen. Bei Eingabe von 0 für den Nenner, soll das Programm mit einer Fehlermeldung beendet werden. Dabei soll die fehlerhafte Eingabe in der TextBox gelöscht werden und der Fokus für die erneute Eingabe auf diese TextBox gesetzt werden. Hinweise Die MessageBox ist eine Klasse, die über statische Methoden zur Erzeugung von Informationsfenstern verfügt. Für die Anwendung sind die folgenden Methoden relevant, mit denen bei einer Falsch-Eingabe beim Nenner die Textbox gelöscht und der Fokus sofort auf die Textbox des Nenners gesetzt wird: TextBox.Clear(); TextBox.Focus(); Im Falle einer nicht zulässigen Eingabe beim Nenner muss die Methode zur Division vorzeitig beendet werden, da ja beim durchführen der Division ansonsten das Programm mit einem Fehler beendet würde. Eine Methode wird mit der folgenden Anweisung vorzeitig beendet: return; Das vorzeitige Beenden einer Methode ist vom Beenden einer Applikation zu unterscheiden. Dieses geschieht durch die Close-Methode der FormKlasse. Die aktuelle Form wird über der Schlüsselwort this angesprochen. this.Close(); - Seite 194 - .NET-Framework & C#.NET NSD Vorgehensweise: Einlesen der Werte für Zähler und Nenner Überprüfung ob der Nenner ungleich 0 ist und Abbruch der Methode für den Fall Nenner gleich null Berechnung des Quotienten Ausgabe des Quotienten - Seite 195 - .NET-Framework & C#.NET Code private void btnRechnen_Click(object sender, EventArgs e) { //Deklarationen double zaehler, nenner, quotient; //Eingabe zaehler = Convert.ToDouble(txbZaehler.Text); nenner = Convert.ToDouble(txbNenner.Text); if (nenner == 0) { MessageBox.Show("Nenner muss ungleich 0 sein!", "Fehler‐Meldung", MessageBoxButtons.OK, MessageBoxIcon.Warning); txbNenner.Clear(); txbNenner.Focus(); return; } //Berechnung quotient = zaehler / nenner; //Ausgabe //lblErgebnis.Text = Convert.ToString(quotient); lblErgebnis.Text = String.Format("{0,12:#,##0.000}", quoti‐ ent); } private void btnEnde_Click(object sender, EventArgs e) { this.Close(); } - Seite 196 - .NET-Framework & C#.NET 10.4.2 Rabatt-Berechnung Programmbeschreibung Mit der nachstehenden Windows-Anwendung soll das bereits bekannt Problem der Rabattberechnung gelöst werden. Es gelten für die Berechnung die folgenden Bedingungen: Umsatz Rabatt < 1000,- € 10% < 2000,- € 20% < 3000,- € 30% sonst 40% Bei Umsatz-Werten, die < oder = 0 sind, erfolgt die nachstehende Fehlermeldung, das Löschen der Eingabe und das Setzen des Fokus auf die EingabeTextBox. - Seite 197 - .NET-Framework & C#.NET NSD Vorgehensweise Einlesen des Wertes für die Variable buttoumsatz Überprüfung der Eingabe und beenden der Methode Falls gilt bruttoumsatz<=0 Gestufte Fallunterscheidung für die Werte <1000, < 2000 und <3000 für den Bruttoumsatz und Berechnung der Variablen rabatt für die einzelnen Fälle. Berechnung der Variablen nettoumsatz. Ausgabe von buttoumsatz, rabatt und nettoumsatz. - Seite 198 - .NET-Framework & C#.NET Code private void btnRechnen_Click(object sender, EventArgs e) { //Deklarationen double bruttoumsatz, rabatt, nettoumsatz; //Eingabe bruttoumsatz = Convert.ToDouble(txbUmsatz.Text); if (bruttoumsatz <= 0) { MessageBox.Show("Umsatz muss größer 0 sein!", "Fehler‐Meldung", MessageBoxButtons.OK, MessageBoxIcon.Warning); txbUmsatz.Clear(); txbUmsatz.Focus(); return; } //Berechnung if (bruttoumsatz < 1000) rabatt = bruttoumsatz * 0.1; else if (bruttoumsatz < 2000) rabatt = bruttoumsatz * 0.2; else if (bruttoumsatz < 3000) rabatt = bruttoumsatz * 0.3; else rabatt = bruttoumsatz * 0.4; nettoumsatz = bruttoumsatz ‐ rabatt; //Ausgabe lblBrutto.Text = String.Format("{0,12:N}", bruttoumsatz); lblRabatt.Text = String.Format("{0,12:N}", rabatt); lblNetto.Text = String.Format("{0,12:N}", nettoumsatz); } private void btnEnde_Click(object sender, EventArgs e) { this.Close(); } - Seite 199 - .NET-Framework & C#.NET 11 DataGridView-Klasse 11.1 DataGridView-Klasse - Überblick Im Namespace System.Windows.Forms gibt es mit der DataGridView-Klasse ein für betriebswirtschaftlicher Anwendungen wichtiges Steuerelement. Der nachstehende Screenshot zeigt eine typsiche Anwendung. DataGridView-Objekt <=> Array Das Steuerelemnt DataGridView korrespondiert bei Berechnungen sehr häufig mit einem Array. Es ist aber wichtig, beides vorn einander zu unterscheiden. Das DataGridView-Objekt ist für die Anzeige (ggf. auch für die Eingabe) von Werten in Form einer Matrix. Das Array ist für Berechnungen im Hauptspeicher. - Seite 200 - .NET-Framework & C#.NET 11.1.1 Grundlegende Strukturen Gerade in den Wirtschaftswissenschaften ist die tabellarische Darstellung eine sehr häufige Form der Präsentation von Daten. In der nachstehenden Abbildung werden in einem DataGridVie-Objekt die Umsatz-Daten nach Filialen und Quartalen dargestellt sowie die Summen für die Zeilen- und Spalten ausgegeben. Um die datentechnische Struktur der DataGridView-Klasse besser zu verstehen, müssen die obigen Begriffe geklärt sein: Column (Spalte) Eine Spalte ist ein Objekt, mit dessen Eigenschaften das generelle Erscheinungsbild aller Elemente dieser Spalte festgelegt wird. Column-Header Überschriftenzelle der Spalte (optional) Row (Zeile) Darstellung der Daten Row-Header Beschriftungszelle der Zeile (optional) Cell Eine Zeile besteht aus mehreren Zellen. Was in diesen Zellen ausgegeben werden kann und wie es formatiert wird, wird durch die Column-Eigenschaften festgelegt. - Seite 201 - .NET-Framework & C#.NET 11.1.2 Exkurs: Collection-Klasse Differenzierung Collection-Klasse (Altglascontainer) Objekte, die die Collection-Klasse sammelt (Flaschen) Wichtig Differenzierung Collection als Objekt Iterms als Objekt Methoden von Collection-Objekten Hinzufügen von Objekten (am Ende anfügen) Add - Methode AddRange - Methode Einfügen an bestimmter Position der Collection-Liste Insert-Methode Löschen von Objekten Clear-Methode Remove-Methode Anzahl der Objekte in der Collection Count-Eigenschaft Indexieren bestimmter Elemente Item-Eigenschaft Besonders wichtig Collection-Objekte werden immer im Plural, Item-Objekte immer im Singular benannt (Row-Objekte Rows-Collection). - Seite 202 - .NET-Framework & C#.NET 11.1.3 Columns- und Rows-Eigenschaft Rows- und Colums-Eigenschaften als Collection-Objekte Rows-Eigenschaft Columns-Eigenschaft Colums-Eigenschaft in Objekt-Hierarchie Eine Spalte kann von einem unterchiedlichen Typ sein. Die nachstehenden Spalten-Klassen sind möglich: Button: DataGridViewButtonColumn CheckBox: DataGridViewCheckBoxColumn Combobox: DataGridViewComboBoxColumn Image: DataGridViewImageColumn Link: DataGridViewLinkColum TextBox: DataGridViewTextBoxColumn Weitere Hierarchie-Ebenen der Columns-Klasse HeaderCell-Eigenschaft (ColumnHeaderCell-Objekt) mit Eigenschaften Styleeigenschaft (CellStyle-Objekt) mit Eigenschaften Ausrichtung Vordergrundfarbe usw. DefaultCellStyle-Eigenschaft (CellStyle-Objekt) mit Eigenschaften S.oben - Seite 203 - .NET-Framework & C#.NET Rows -Eigenschaft in Objekt-Hierarchie Struktur: Auf der obersten Ebene steht wieder das DataGridView-Objekt. In der zweiten Ebene folgt die Rows-Eigenschaft, ein Collection-Objekt, das die Zeilen verwaltet. Diese Zeilen stellen die dritte Ebene dar. Eine Zeile verfügt nun wiederum über die Cells-Eigenschaft, die die Zellen einer Zeile verwaltet. Diese Zellen stellen die letzte Ebene der Grafik dar. Die Anzahl der Zellen und deren Erscheinungsbild richtet sich nach den definierten Columns. - Seite 204 - .NET-Framework & C#.NET 11.1.4 Aufbau eines DataGridView-Objektes Anwendung Der Anwender gibt die Daten in die Textboxen ein und überträgt diese durch Klicken des Button DatenErfassung in das Grid. Dabei wird bei jedem Übertragen zuerst eine neue Row im Grid eingerichtet und dann erst die Daten dort gespeichert. Jeder neue Datensatz wird also hinten in der Collection der Rows angefügt. Teilprobleme Aufbau des DataGridView-Objekts Übertrgaung der Daten Vorgehensoptionen - Seite 205 - .NET-Framework & C#.NET Manueller, unformatierter Grid-Aufbau Event-Handling neuer Button sowie Klick-Event im Rahmen der Übertragung der Werte von den TextBoxen in das Grid Load-Event der Form Ein Load-Event der Form erzeugt man wie gewohnt durch das Doppelklicken auf die Form. Beachten Sie dabei, dass auf die Form und nicht auf ein Steuerelement auf der Form klicken dürfen. private void frmUmsaetze_Load(object sender, EventArgs e) { } Code Name-Eigenschaft des DataGridView-Objekts: grdUmsaetze Spalten Name der Filiale; Umsatz von vier Quartalen => 5 Spalten grdUmsaetze.ColumnCount = 5; Zeilen Die Zeilenanzahl ist in diesem Fall abhängig von der Anzahl der Eingaben und damit vorher nicht bekannt. Weitere Einstellungen Die weiteren Anweisungen haben die die folgenden Wirkungen: Spalten-Header ausgeblendet Zeilen-Header ausgeblendet Option zum Einfügen neuer Zeilen durch den Anwender deaktivieren Grid schreibschützen Syntax private void frmUmsaetze_Load(object sender, EventArgs e) { //Gridaufbau grdUmsaetze.ColumnCount = 6; grdUmsaetze.RowCount = 1; grdUmsaetze.ColumnHeadersVisible = false; grdUmsaetze.RowHeadersVisible = false; grdUmsaetze.AllowUserToAddRows = false; grdUmsaetze.ReadOnly = true; } - Seite 206 - .NET-Framework & C#.NET 11.1.5 Schematische Darstellung von Rows & Cells Nachstehend eine schematische Darstellung des DataGridView-Objekts zum besseren Verständnis des Zugriffs auf Zellen. Spalte 1 Columns[0] Spalte 2 Columns[1] Spalte 3 Columns[2] Spalte 4 Columns[3] Spalte 5 Columns[4] Zeile 1 Rows[0].Cells[0] Rows[0].Cells[1] Rows[0].Cells[2] Rows[0].Cells[3] Rows[0].Cells[4] Rows[0] Zeile 2 Rows[1].Cells[0] Rows[1] Zeile 3 Rows[2].Cells[0] Rows[2] Zugriff auf eine Zelle Der Zugirff - egal ob lesend oder schreibend - auf die zelle eines DataGridView-Objekts ist die zentrale Funktionalität. Dafür muss die entsprechende Row der Rows-Collection und die entsprechende Cell (d.h. die Spalte) der Cells-Collection einer Row angesprochen werden. Diese geschieht durch die Angabe des Indexes in eckigen Klammern hinter dem entsprechenden Collection-Objekt. grdUmsaetzte.Rows[0].Cells[1].... Value-Eigenschaft einer Zelle Eine Zelle selber ist ein Objekt und besitzt eine Reihe von Membern. Wert in Zelle ausgeben grdUmsaetzte.Rows[0].Cells[1].Value = "Test"; Wert aus Zelle lesen label.Text = grdUmsaetzte.Rows[0].Cells[1].Value; Achtung! Die Verwaltung der Rows- und Colums-Items ist nullbasiert! - Seite 207 - .NET-Framework & C#.NET 11.1.6 Variabler Zugriff auf Rows & Cells DataGridView-Objekt - Schematische Darstellung von Rows & Cells Spalte 1 Columns[0] Spalte 2 Columns[1] Spalte 3 Columns[2] Spalte 4 Columns[3] Spalte 5 Columns[4] Zeile 1 Rows[0].Cells[0] Rows[0].Cells[1] Rows[0].Cells[2] Rows[0].Cells[3] Rows[0].Cells[4] Rows[0] Zeile 2 Rows[1].Cells[0] Rows[1] Zeile 3 Rows[2].Cells[0] Rows[2] Variabler Zugriff auf eine Zelle Durch entspreichende Schleifen für die Variablen zeile und spalte kann jede beliebige Zelle des Grids adressiert werden. grdUmsaetzte.Rows[zeile].Cells[spalte].Value = "Test"; Fehlerhafte Lösung grdUmsaetze.Rows[0].Cells[0].Value = txbFiliale.Text; grdUmsaetze.Rows[0].Cells[1].Value = txbQ1.Text; ... Wie konstruiert man aber eine sinnvolle Variable für den Zeilen-Index? Hinzufügen einer neuen Row im Grid grdUmsaetze.RowCount = grdUmsaetze.RowCount + 1; grdUmsaetze.RowCount++; Variable Adressierung einer Row Die Daten sollen in der zuletzt hinzugefügten Row gespeichert werden. RowCount-Eigenschaft des DataGridView-Objekts liefert die Anzahl der Zeilen im Grid. Der Index dieser letzten Zeile ist RowCount – 1 (Index ist nullbasiert). Code private void btnErfassen_Click(object sender, EventArgs e) { //Deklarationen int dsn; //Prozedur grdUmsaetze.RowCount = grdUmsaetze.RowCount + 1; dsn = grdUmsaetze.RowCount; grdUmsaetze.Rows[dsn ‐ 1].Cells[0].Value = txbFiliale.Text; grdUmsaetze.Rows[dsn ‐ 1].Cells[1].Value = txbQ1.Text; grdUmsaetze.Rows[dsn ‐ 1].Cells[2].Value = txbQ2.Text; grdUmsaetze.Rows[dsn ‐ 1].Cells[3].Value = txbQ3.Text; grdUmsaetze.Rows[dsn ‐ 1].Cells[4].Value = txbQ4.Text; - Seite 208 - .NET-Framework & C#.NET 11.2 Berechnungen - Grid <=> Array Der nachfolgende Screenshot zeigt eine Erweiterung der bisher bekannten Aufgabenstellung. Nach der Erfassung und Übertragung der Daten ins Grid erfolgt die Berechnung der Zeilen- und Spaltensummen. Diese Methode wird durch das Klicken auf den Button „Berechnungen“ ausgelöst. Eine direkte Berechnung im Grid ist problematisch und nicht sinnvoll. Wir haben aber bereits solche Berechnungen bei den Konsolenanwendungen in einem Array durchgeführt. Damit sind drei Phase bei der Berechnung zu unterscheiden: Dimensionierung des Arrays Übertragung der Wert: Grid => Array Berechnungen im Array Übertragung der Ergebnisse: Array => Grid Wenn man die Problematik genauer betrachtet, wird klar, dass die Berechnungen im Array bereits bei den Konsolen-Anwendungen behandelt wurden. - Seite 209 - .NET-Framework & C#.NET 11.2.1 Dimensionierung des Arrays Die nachfolgende Grafik veranschaulicht die Strukturen von Grid und Array. Es wird eine beliebige Anzahl von Zeilen erfasst - z.B. 10 Zeilen. Die RowCount-Eigenschaft hat dann den Wert 10. Der Index der letzten Zeile hat dann den Wert 10-1=9. Zeilenanzahl Da alle Zeilen aus dem Grid in das Array übertragen werden sollen => Anzahl der Zeilen im Array = Wert der RowCount-Eigenschaft. Zusätzlich sind die Spaltensummen zu berechnen => Anzahl der Zeilen +1 oder RowCount + 1. Spaltenanzahl Das Grid hat einschließlich der Summenspalte 6 Spalten. Allerdings steht in der ersten Spalte die Bezeichnung der Filiale. Nicht relevant für die Berechnungen. In einem numerischen Array nicht speicherbar. Insgesamt benötigen wir damit im Array nur 5 Spalten. Code private void btnRechnung_Click(object sender, EventArgs e) { //Deklarationen int anzahl, zeile, spalte; double[,] aryUmsaetze; //Array ensprechend der Rows deklarieren anzahl = grdUmsaetze.Rows.Count; aryUmsaetze = new double[anzahl + 1, 5]; - Seite 210 - .NET-Framework & C#.NET 11.2.2 Übertragung der Daten: Grid => Array Nach dem das Array instanziiert ist, können die Daten vom Grid in das Array übertragen werden. Übertragung des 1. Wertes aryUmsaetze[0, 0] = Convert.ToDouble (grdUmsaetze.Rows[0].Cells[1].Value); Achtung: Spalten-Index ist im Grid um 1 höher als im Array Übertragung aller Werte der 1. Zeile Schlechte Lösung aryUmsaetze[0, 0] = Convert.ToDouble (grdUmsaetze.Rows[0].Cells[1].Value); aryUmsaetze[0, 1] = Convert.ToDouble (grdUmsaetze.Rows[0].Cells[2].Value); … For-Schleife //Daten einlesen for (spalte = 0; spalte <= 3; spalte++) aryUmsaetze[0, spalte] = Convert.ToDouble( grdUmsaetze.Rows[0].Cells[spalte+1].Value); - Seite 211 - .NET-Framework & C#.NET Übertragung aller Zeilen Schlechte Lösung nicht effizient Anzahl der Zeilen nicht bekannt, daher nicht programmierbar //Daten einlesen for (spalte = 0; spalte <= 3; spalte++) aryUmsaetze[0, spalte] = Convert.ToDouble( grdUmsaetze.Rows[0].Cells[spalte+1].Value); for (spalte = 0; spalte <= 3; spalte++) aryUmsaetze[1, spalte] = Convert.ToDouble( grdUmsaetze.Rows[1].Cells[spalte+1].Value); … For-Schleife //Daten einlesen for (zeile = 0; zeile <= anzahl ‐ 1; zeile++) for (spalte = 0; spalte <= 3; spalte++) aryUmsaetze[zeile, spalte] = Convert.ToDouble (grdUmsaetze.Rows[zeile].Cells[spalte+1].Value); - Seite 212 - .NET-Framework & C#.NET 11.2.3 Berechnungen im Array Die Grafik verdeutlicht noch einmal die zu berechnenden Zellen. Code private void btnRechnung_Click(object sender, EventArgs e) { //Deklarationen int anzahl, zeile, spalte; double[,] aryUmsaetze; //Array ensprechend der Rows deklarieren anzahl = grdUmsaetze.Rows.Count; aryUmsaetze = new double[anzahl + 1, 5]; //Daten einlesen for (zeile = 0; zeile <= anzahl ‐ 1; zeile++) for (spalte = 0; spalte <= 3; spalte++) aryUmsaetze[zeile, spalte] = Convert.ToDouble (grdUmsaetze.Rows[zeile].Cells[spalte+1].Value); //Zeilensummen for (zeile = 0; zeile <= anzahl ‐ 1; zeile++) for (spalte = 0; spalte <= 3; spalte++) aryUmsaetze[zeile, 4] = aryUmsaetze[zeile, 4] + aryUmsaetze[zeile, spalte]; //Spaltensummen for (spalte = 0; spalte <= 4; spalte++) for (zeile = 0; zeile <= anzahl ‐ 1; zeile++) aryUmsaetze[anzahl, spalte]= aryUmsaetze[anzahl, spalte] + aryUmsaetze[zeile, spalte]; - Seite 213 - .NET-Framework & C#.NET 11.2.4 Übertragung der Daten: Array => Grid Bei der Rückübertragung der Daten ins DataGridView-Objekt stellen wir zwei Varianten vor. Übertragung der gesamten Werte des Arrays in das Grid. Übertragung der Zeilen- und Spalten-Summen. Version 1 Übertragung des 1. Wertes grdUmsaetze.Rows[0].Cells[1].Value aryUmsaetze[0,0]; Übertragung aller Werte der 1. Zeile Schlechte Variante grdUmsaetze.Rows[0].Cells[1].Value grdUmsaetze.Rows[0].Cells[2].Value grdUmsaetze.Rows[0].Cells[3].Value grdUmsaetze.Rows[0].Cells[4].Value grdUmsaetze.Rows[0].Cells[5].Value aryUmsaetze[0,0]; aryUmsaetze[0,1]; aryUmsaetze[0,2]; aryUmsaetze[0,3]; aryUmsaetze[0,4]; Effiziente Variante for (spalte = 0; spalte <= 4; spalte++) grdUmsaetze.Rows[0].Cells[spalte + 1].Value = aryUmsaetze[0, spalte]; - Seite 214 - .NET-Framework & C#.NET Übertragung aller Zeilen Schlechte Variante for (spalte = 0; spalte <= 4; spalte++) grdUmsaetze.Rows[0].Cells[spalte + 1].Value = aryUmsaetze[0, spalte]; for (spalte = 0; spalte <= 4; spalte++) grdUmsaetze.Rows[1].Cells[spalte + 1].Value = aryUmsaetze[1, spalte]; for (spalte = 0; spalte <= 4; spalte++) grdUmsaetze.Rows[2].Cells[spalte + 1].Value = aryUmsaetze[2, spalte]; ... Effiziente Variante for (zeile = 0; zeile <= anzahl; zeile++) for (spalte = 0; spalte <= 4; spalte++) grdUmsaetze.Rows[zeile].Cells[spalte + 1].Value = aryUmsaetze[zeile, spalte]; Summenzeile //Daten ausgeben grdUmsaetze.RowCount = grdUmsaetze.RowCount + 1; for (zeile = 0; zeile <= anzahl; zeile++) for (spalte = 0; spalte <= 4; spalte++) grdUmsaetze.Rows[zeile].Cells[spalte + 1].Value = aryUmsaetze[zeile, spalte]; Version 2 //Daten ausgeben grdUmsaetze.RowCount = grdUmsaetze.RowCount + 1; //ZeilenSummen for (zeile = 0; zeile <= anzahl-1; zeile++) grdUmsaetze.Rows[zeile].Cells[5].Value = aryUmsaetze[zeile, 4]; //Spaltensummen for (spalte = 0; spalte <= 4; spalte++) grdUmsaetze.Rows[anzahl].Cells[spalte + 1].Value = aryUmsaetze[anzahl, spalte]; - Seite 215 - .NET-Framework & C#.NET 11.3 Optische Gestaltung des DataGridView-Objekts Bisher ist die optische Aufbereitung der Ausgabe im Grid nicht sonderlich ansprechend. In den beiden folgenden Abschnitten zeigen wir anhand von zwei Vorgehensweisen wie ein Grid formatiert werden kann. Die nachstehende Abbildung zeigt das Ziel unserer Überlegungen. Der erste Weg ist etwas mühseliger, dafür aber übersichtlicher programmiert. Es werden die einzelnen Spalten formatiert und dann dem Gerät hinzugefügt. Bei der zweiten Variante arbeiten wir mit Formatierungsvorlagen, die wir dann jeder Spalte zuweisen. - Seite 216 - .NET-Framework & C#.NET 11.3.1 Objekthierarchie Um die Formatierung des Grids besser zu verstehen, muss die bereits bekannte Objekthierarchie weiter vertieft werden. Wichtige Eigenschaften HeaderText-Eigenschaft Text der Kopfzelle HeaderCell-Eigenschaft DataGridViewColumnHeaderCell-Objekt, das die Kopfzelle darstellt mit weiteren Eigenschaften DefaultCellStyle-Eigenschaft DatGridViewCellStyle-Objekt mit weiteren Eigenschaften - Seite 217 - .NET-Framework & C#.NET Grundprinzip Bisher haben wie die Spalten eines DataGridView-Objekts durch die folgende simple Anweisung eingerichtet. private void frmUmsaetze_Load(object sender,EventArgs e) { //Gridaufbau grdUmsaetze.ColumnCount = 6; Instanziierung von Spalten private void frmUmsaetze_Load(object sender,EventArgs e) { //Deklarationen DataGridViewTextBoxColumn filiale = new DataGridViewTextBoxColumn(); DataGridViewTextBoxColumn quartal1 = new DataGridViewTextBoxColumn(); DataGridViewTextBoxColumn quartal2 = new DataGridViewTextBoxColumn(); DataGridViewTextBoxColumn quartal3 = new DataGridViewTextBoxColumn(); DataGridViewTextBoxColumn quartal4 = new DataGridViewTextBoxColumn(); DataGridViewTextBoxColumn summe = new DataGridViewTextBoxColumn(); - Seite 218 - .NET-Framework & C#.NET 11.3.2 Gestaltung durch CellStyle-Eigenschaften DefaultCellStyle-Eigenschaften Formatierung der Daten einer Spalte DefaultCellStyle-Eigenschaften = DataGridViewCellStyle-Objekt Eigenschaften des DataGridViewCellStyle-Objekts: Alignment-Eigenschaft Color-Eigenschaft Format-Eigenschaft Name-Eigenschaft Formatierung für die erste und die zweite Spalte (weitere Spalten analog) //Spaltenaufbau & Spaltenformate filiale.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleLeft; filiale.DefaultCellStyle.BackColor = Color.LightBlue; filiale.DefaultCellStyle.ForeColor = Color.DarkRed; filiale.Name = "Filiale"; quartal1.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight; quartal1.DefaultCellStyle.Format = "#,##0.00 €"; quartal1.DefaultCellStyle.NullValue = null; quartal1.Name = "Quartal1"; - Seite 219 - .NET-Framework & C#.NET Formatierung der Header-Zelle der Spalten Klassen-Hierarchie der Header-Zelle HeaderText-Eigenschaft (Eigenschaft des Column-Objekts) HeaderCell.Style.Alignment-Eigenschaft Zugriff auf das DataGridViewCellStyle-Objekt: HeaderCell.Style. ... Code //Spaltenaufbau & Spaltenformate filiale.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleLeft; filiale.DefaultCellStyle.BackColor = Color.LightBlue; filiale.DefaultCellStyle.ForeColor = Color.DarkRed; filiale.HeaderText = "Standort"; filiale.HeaderCell.Style.Alignment = DataGridViewContentAlignment.MiddleCenter; filiale.Name = "Filiale"; quartal1.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight; quartal1.DefaultCellStyle.Format = "#,##0.00 €"; quartal1.DefaultCellStyle.NullValue = null; quartal1.HeaderText = "1. Quartal"; quartal1.HeaderCell.Style.Alignment = DataGridViewContentAlignment.MiddleCenter; quartal1.Name = "Quartal1"; - Seite 220 - .NET-Framework & C#.NET 11.3.3 Zugriff über Name-Eigenschaft Der Name ermöglicht den Zugriff auf eine Spalte bzw. Zelle über diesen Beezichner anstatt des Indexes. Der Code wird damit lesbarer und Verwechselungen werden unwahrscheinlicher. private void btnErfassen_Click(object sender, EventArgs e) { //Deklarationen int dsn; //Zeilenanzahl erhöhen & DSN ermitteln grdUmsaetze.RowCount = grdUmsaetze.RowCount + 1; dsn = grdUmsaetze.RowCount; //Zellen der Row über Namen ansprechen grdUmsaetze.Rows[dsn ‐ 1].Cells["Filiale"].Value = txbFiliale.Text; grdUmsaetze.Rows[dsn ‐ 1].Cells["Quartal1"].Value = Convert.ToDouble(txbQ1.Text); grdUmsaetze.Rows[dsn ‐ 1].Cells["Quartal2"].Value = Convert.ToDouble(txbQ2.Text); grdUmsaetze.Rows[dsn ‐ 1].Cells["Quartal3"].Value = Convert.ToDouble(txbQ3.Text); grdUmsaetze.Rows[dsn ‐ 1].Cells["Quartal4"].Value = Convert.ToDouble(txbQ4.Text); } - Seite 221 - .NET-Framework & C#.NET 11.3.4 Gestaltung durch CellStyle-Objekte CellStyle-Objekte Definition von CellStyle-Objekten (Muster) für jedes Format und Zuweisung dieses Musters zu den Eigenschaften. Notwendige Formate: die erste Datenspalte, die übrigen Datenspalten und die Kopfzeile, Instanziierung der Format-Objekte grdFormat1 für die erste Spalte, grdFormat2 für die übrigen Spalten und grdFormatHeader. Code private void frmUmsaetze_Load(object sender, EventArgs e) { //Deklarationen //CellStyle‐Objekte DataGridViewCellStyle grdFormat1 = new DataGridViewCellStyle(); DataGridViewCellStyle grdFormat2 = new DataGridViewCellStyle(); DataGridViewCellStyle grdFormatHeader = new DataGridViewCellStyle(); - Seite 222 - .NET-Framework & C#.NET Einrichtung der Muster-Formate //Aufbau der CellStyle‐Objekte grdFormatHeader.BackColor = Color.LightBlue; grdFormatHeader.ForeColor = Color.Black; grdFormatHeader.Alignment = DataGridViewContentAlignment.MiddleCenter; grdFormat1.Alignment = DataGridViewContentAlignment.MiddleLeft; grdFormat1.BackColor = Color.Aquamarine; grdFormat1.ForeColor = Color.DarkRed; grdFormat2.Alignment = DataGridViewContentAlignment.MiddleRight; grdFormat2.Format = "#,##0.00 €"; grdFormat2.ForeColor = Color.DarkMagenta; grdFormat2.BackColor = Color.LightGray; grdFormat2.NullValue = null; Zuweisung der Formate //Aufbau der Spalten filiale.DefaultCellStyle = grdFormat1; filiale.HeaderText = "Standort"; filiale.HeaderCell.Style = grdFormatHeader; filiale.Name = "Filiale"; quartal1.DefaultCellStyle = grdFormat2; quartal1.HeaderText = "1. Quartal"; quartal1.HeaderCell.Style = grdFormatHeader; quartal1.Name = "Quartal1"; quartal2.DefaultCellStyle = grdFormat2; quartal2.HeaderText = "2. Quartal"; quartal2.HeaderCell.Style = grdFormatHeader; quartal2.Name = "Quartal2"; - Seite 223 - .NET-Framework & C#.NET 11.4 Übungen & Fragen 11.4.1 Kapital-Verlauf (Variante 1) Mit der nachstehenden Anwendung soll der Verlauf eines angelegten Kapitals veranschaulicht werden. Die Berechnungen solle rekursiv Jahr für Jahr erfolgen. Es sind keine Berechnungen im Array notwendig. ScreenShot Code //Deklarationen DataGridViewTextBoxColumn jahr = new DataGridViewTextBoxColumn(); DataGridViewTextBoxColumn kapital = new DataGridViewTextBoxColumn(); double startKapital, zinssatz, endKapital; int laufzeit, j; //Spaltenaufbau jahr.DefaultCellStyle.Format = "#0"; jahr.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter; jahr.HeaderCell.Style.Alignment = DataGridViewContentAlignment.MiddleCenter; jahr.Width = 100; jahr.Name = "Jahr"; - Seite 224 - .NET-Framework & C#.NET kapitalDefaultCellStyle.Format = "#,##0.00 €"; kapital.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter; kapital.HeaderCell.Style.Alignment = DataGridViewContentAlignment.MiddleCenter; ; kapital.Width = 200; kapital.Name = "Kapital"; //Gridaufbau grdKapital.Columns.AddRange(jahr, kapital); grdKapital.RowCount = 1; grdKapital.Width = 300 + 25; grdKapital.RowHeadersVisible = false; grdKapital.AllowUserToAddRows = false; grdKapital.ReadOnly = true; grdKapital.Visible = true; //Werte einlesen startKapital = Convert.ToDouble(txbKapital.Text); zinssatz = Convert.ToDouble(txbZinssatz.Text); laufzeit = Convert.ToInt32 (txbLaufzeit.Text); //Berechnungen und Ausgabe grdKapital.RowCount = laufzeit; endKapital = startKapital; for (j = 0; j < laufzeit; j++) { endKapital = endKapital * (1 + zinssatz / 100); grdKapital.Rows[j].Cells["Jahr"].Value = j + 1; grdKapital.Rows[j].Cells["Kapital"].Value = endKapital; } - Seite 225 - .NET-Framework & C#.NET 11.4.2 Kapital-Verlauf (Variante 2) Bei der nachstehenden Variante handelt es sich nur um die optisch aufbereitete Version der obigen Kapitalanlage. ScreenShot Code //Deklarationen DataGridViewCellStyle frmZelleKapital = new DataGrid‐ ViewCellStyle(); DataGridViewCellStyle frmZelleJahr = new DataGridViewCellStyle(); DataGridViewCellStyle frmHeader = new DataGridViewCellStyle(); DataGridViewTextBoxColumn Jahr = new DataGridViewTextBoxColumn(); DataGridViewTextBoxColumn Kapital = new DataGridViewTextBoxCol‐ umn(); double startKapital, zinssatz, endKapital; int laufzeit, j; //Formate frmZelleKapital.Alignment = DataGridViewContentAlignment.Middle‐ Center; frmZelleKapital.BackColor = Color.AntiqueWhite; frmZelleKapital.ForeColor = Color.Chocolate; frmZelleKapital.Format = "#,##0.00 €"; frmZelleJahr.Alignment = DataGridViewContentAlignment.Middle‐ Center; frmZelleJahr.BackColor = Color.AntiqueWhite; frmZelleJahr.ForeColor = Color.Chocolate; frmZelleJahr.Format = "#0"; - Seite 226 - .NET-Framework & C#.NET frmHeader.Alignment = DataGridViewContentAlignment.MiddleCenter; frmHeader.BackColor = Color.Wheat; frmHeader.ForeColor = Color.Black; //Spaltenaufbau Jahr.DefaultCellStyle = frmZelleJahr; Jahr.HeaderText = "Jahr"; Jahr.HeaderCell.Style = frmHeader; Jahr.Width = 100; Jahr.Name = "Jahr"; Kapital.DefaultCellStyle = frmZelleKapital; Kapital.HeaderText = "Kapital"; Kapital.HeaderCell.Style = frmHeader; Kapital.Width = 200; Kapital.Name = "Kapital"; //Gridaufbau grdKapital.Columns.AddRange(Jahr, Kapital); grdKapital.RowCount = 1; grdKapital.Width = 300 + 25; grdKapital.RowHeadersVisible = false; grdKapital.AllowUserToAddRows = false; grdKapital.ReadOnly = true; grdKapital.Visible = true; //Werte einlesen - Seite 227 - .NET-Framework & C#.NET 11.4.3 Endwert-Methode (Variante 1) Bei der nachstehenden Anwendung soll noch einmal die bekannt Endwert-Methode der Investitionsrechung als Windows-Anwendung realisiert werden. ScreenShot Code private void btnRechnung_Click(object sender, EventArgs e) { //Deklarationen double investition, cashFlow, zinssatz, endwert, zinsen; int laufzeit, j; //Werte einlesen investition = Convert.ToDouble(txbInvestition.Text); cashFlow = Convert.ToDouble(txbCashFlow.Text); zinssatz = Convert.ToDouble(txbZinsSatz.Text); laufzeit = Convert.ToInt32(txbLaufzeit.Text); //Berechnungen & Ausgabe grdKW.RowCount = laufzeit; endwert = investition * (‐1); for (j = 1; j <= laufzeit; j++) { zinsen = endwert * zinssatz / 100; endwert = endwert + zinsen + cashFlow; grdKW.Rows[j ‐ 1].Cells["clJahr"].Value = j; grdKW.Rows[j ‐ 1].Cells["clCashFlow"].Value = cashFlow; grdKW.Rows[j ‐ 1].Cells["clZinsen"].Value = zinsen; grdKW.Rows[j ‐ 1].Cells["clEndwert"].Value = endwert; } } - Seite 228 - .NET-Framework & C#.NET private void frmEndwert_Load(object sender, EventArgs e) { //Deklarationen DataGridViewTextBoxColumn clJahr = new DataGridViewTextBoxColumn(); DataGridViewTextBoxColumn clCashFlow = new DataGridViewTextBoxColumn(); DataGridViewTextBoxColumn clZinsen = new DataGridViewTextBoxColumn(); DataGridViewTextBoxColumn clEndwert = new DataGridViewTextBoxColumn(); //Spaltenaufbau clJahr.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter; clJahr.DefaultCellStyle.Format = "#0"; clJahr.HeaderCell.Style.Alignment = DataGridViewContentAlignment.MiddleCenter; clJahr.Width = 50; clJahr.HeaderText = "Jahr"; clJahr.Name = "clJahr"; clCashFlow.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter; clCashFlow.DefaultCellStyle.Format = "#,##0.00 €"; clCashFlow.HeaderCell.Style.Alignment = DataGridViewContentAlignment.MiddleCenter; clCashFlow.Width = 100; clCashFlow.HeaderText = "Cash Flow"; clCashFlow.Name = "clCashFlow"; clZinsen.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter; clZinsen.DefaultCellStyle.Format = "#,##0.00 €"; clZinsen.HeaderCell.Style.Alignment = DataGridViewContentAlignment.MiddleCenter; clZinsen.Width = 100; clZinsen.HeaderText = "Zinsen"; clZinsen.Name = "clZinsen"; clEndwert.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter; clEndwert.DefaultCellStyle.Format = "#,##0.00 €"; clEndwert.HeaderCell.Style.Alignment = DataGridViewContentAlignment.MiddleCenter; clEndwert.Width = 100; clEndwert.HeaderText = "Endwert"; clEndwert.Name = "clEndwert"; - Seite 229 - .NET-Framework & C#.NET //Gridaufbau grdKW.Columns.AddRange(clJahr, clCashFlow, clZinsen, clEndwert); grdKW.RowCount = 1; grdKW.Width = 350 + 25; grdKW.RowHeadersVisible = false; grdKW.AllowUserToAddRows = false; grdKW.ReadOnly = true; grdKW.Visible = true; } - Seite 230 - .NET-Framework & C#.NET 11.4.4 Endwert-Methode (Variante 2) Nachstehend nun wieder die Variante mit der besseren optischen Aufbereitung. Die Änderungen beziehen sich im Wesentlichen auf die Programmierung in der Form-Load-Methode. ScreenShot Code //Deklarationen DataGridViewCellStyle frmZelleEW = new DataGridViewCellStyle(); DataGridViewCellStyle frmZelleJahr = new DataGridViewCellStyle(); DataGridViewCellStyle frmHeader = new DataGridViewCellStyle(); DataGridViewTextBoxColumn clJahr = new DataGridViewTextBoxColumn(); DataGridViewTextBoxColumn clCashFlow = new DataGridViewTextBoxColumn(); DataGridViewTextBoxColumn clZinsen = new DataGridViewTextBoxColumn(); DataGridViewTextBoxColumn clEndwert = new DataGridViewTextBoxColumn(); //Formate frmZelleEW.Alignment = DataGridViewContentAlignment.MiddleCenter; frmZelleEW.BackColor = Color.AntiqueWhite; frmZelleEW.ForeColor = Color.Chocolate; frmZelleEW.Format = "#,##0.00 €"; - Seite 231 - .NET-Framework & C#.NET frmZelleJahr.Alignment = DataGridViewContentAlignment.MiddleCenter; frmZelleJahr.BackColor = Color.AntiqueWhite; frmZelleJahr.ForeColor = Color.Chocolate; frmZelleJahr.Format = "#0"; frmHeader.Alignment = DataGridViewContentAlignment.MiddleCenter; frmHeader.BackColor = Color.Wheat; frmHeader.ForeColor = Color.Black; //Spaltenaufbau clJahr.DefaultCellStyle = frmZelleJahr; clJahr.HeaderText = "Jahr"; clJahr.HeaderCell.Style = frmHeader; clJahr.Width = 50; clJahr.Name = "clJahr"; clCashFlow.DefaultCellStyle = frmZelleEW; clCashFlow.HeaderText = "Cash Flow"; clCashFlow.HeaderCell.Style = frmHeader; clCashFlow.Width = 100; clCashFlow.Name = "clCashFlow"; clZinsen.DefaultCellStyle = frmZelleEW; clZinsen.HeaderText = "Zinsen"; clZinsen.HeaderCell.Style = frmHeader; clZinsen.Width = 100; clZinsen.Name = "clZinsen"; clEndwert.DefaultCellStyle = frmZelleEW; clEndwert.HeaderText = "Endwert"; clEndwert.HeaderCell.Style = frmHeader; clEndwert.Width = 100; clEndwert.Name = "clEndwert"; //Gridaufbau grdKW.Columns.AddRange(clJahr, clCashFlow, clZinsen, clEndwert); grdKW.RowCount = 1; grdKW.Width = 350 + 25; grdKW.RowHeadersVisible = false; grdKW.AllowUserToAddRows = false; grdKW.ReadOnly = true; grdKW.Visible = true; - Seite 232 - .NET-Framework & C#.NET 11.4.5 Lotto-Gewinn Bei der nachstehenden Aufgabe soll bei einem Lottogewinn, einer Entnahme pro Jahr und einem Ertragszins der Kapitalverlauf des Gewinns dargestellt werden. Das Modell bricht ab, wenn der Gewinn aufgebraucht ist. Von daher ist darauf zu achten, daß die jährlichen Entnahmen höher als die jährlichen Zinsen sind. ScreenShot Code private void btnRechnung_Click(object sender, EventArgs e) { //Deklarationen double gewinn, entnahme, zinssatz, endwert, zinsen; int j; //Werte einlesen gewinn = Convert.ToDouble(txbKapital.Text); entnahme = Convert.ToDouble(txbEntnahme.Text); zinssatz = Convert.ToDouble(txbZinsSatz.Text); //Berechnungen & Ausgabe j = 0; endwert = gewinn; while (endwert > 0 & j < 100) { j++; grdKapital.RowCount = grdKapital.RowCount + 1; zinsen = endwert * zinssatz / 100; endwert = endwert + zinsen ‐ entnahme; grdKapital.Rows[j ‐ 1].Cells["clJahr"].Value = j; grdKapital.Rows[j ‐ 1].Cells["clEntnahme"].Value = entnahme; grdKapital.Rows[j ‐ 1].Cells["clZinsen"].Value = zinsen; grdKapital.Rows[j ‐ 1].Cells["clEndwert"].Value = endwert; } } - Seite 233 - .NET-Framework & C#.NET private void Form1_Load(object sender, EventArgs e) { //Deklarationen DataGridViewCellStyle frmZelle = new DataGridViewCellStyle(); DataGridViewCellStyle frmZelleJahr = new DataGridViewCellStyle(); DataGridViewCellStyle frmHeader = new DataGridViewCellStyle(); DataGridViewTextBoxColumn clJahr = new DataGridViewTextBoxColumn(); DataGridViewTextBoxColumn clEntnahme = new DataGridViewTextBoxColumn(); DataGridViewTextBoxColumn clZinsen = new DataGridViewTextBoxColumn(); DataGridViewTextBoxColumn clEndwert = new DataGridViewTextBoxColumn(); //Formate frmZelle.Alignment = DataGridViewContentAlignment.MiddleCenter; frmZelle.BackColor = Color.AntiqueWhite; frmZelle.ForeColor = Color.Chocolate; frmZelle.Format = "#,##0.00 €"; frmZelleJahr.Alignment = DataGridViewContentAlignment.MiddleCenter; frmZelleJahr.BackColor = Color.AntiqueWhite; frmZelleJahr.ForeColor = Color.Chocolate; frmZelleJahr.Format = "#0"; frmHeader.Alignment = DataGridViewContentAlignment.MiddleCenter; frmHeader.BackColor = Color.Azure; frmHeader.ForeColor = Color.Black; //Spaltenaufbau clJahr.DefaultCellStyle = frmZelleJahr; clJahr.HeaderText = "Jahr"; clJahr.HeaderCell.Style = frmHeader; clJahr.Width = 50; clJahr.Name = "clJahr"; clEntnahme.DefaultCellStyle = frmZelle; clEntnahme.HeaderText = "Entnahme"; clEntnahme.HeaderCell.Style = frmHeader; clEntnahme.Width = 100; clEntnahme.Name = "clEntnahme"; - Seite 234 - .NET-Framework & C#.NET clZinsen.DefaultCellStyle = frmZelle; clZinsen.HeaderText = "Zinsen"; clZinsen.HeaderCell.Style = frmHeader; clZinsen.Width = 100; clZinsen.Name = "clZinsen"; clEndwert.DefaultCellStyle = frmZelle; clEndwert.HeaderText = "Endwert"; clEndwert.HeaderCell.Style = frmHeader; clEndwert.Width = 100; clEndwert.Name = "clEndwert"; //Gridaufbau grdKapital.Columns.AddRange(clJahr, clEntnahme, clZinsen, clEndwert); grdKapital.RowCount = 1; grdKapital.Width = 350 + 25; grdKapital.RowHeadersVisible = false; grdKapital.AllowUserToAddRows = false; grdKapital.ReadOnly = true; grdKapital.Visible = true; } - Seite 235 - .NET-Framework & C#.NET 11.4.6 Prämien-Berechung Mit dem nachstehenden Programm soll Prämien für Mitarbeiter nach der Betriebszugehörigkeit berechnet werden. Mit dem Button „btnErfassen“ werden die Daten Nachnamen, Betriebszugehörigkeit und Gehalt erfaßt und in das Grid übertragen. Mit dem Button „btnRchnung“ werden die Daten aus den Spalten Dienstzeit und Gehalt in ein entsprechendes Array übertragen, die Prämie, die Summe und die Spaltensumme berechnet und ausgegeben. ScreenShot Code private void btnErfassen_Click(object sender, EventArgs e) { //Deklarationen int z; //Prozedur grdPraemie.RowCount++; z = grdPraemie.RowCount ‐ 1; grdPraemie.Rows[z].Cells["clName"].Value = txbName.Text; grdPraemie.Rows[z].Cells["clJahre"].Value = Convert.ToDouble(txbJahre.Text); grdPraemie.Rows[z].Cells["clGehalt"].Value = Convert.ToDouble(txbGehalt.Text); txbName.Clear(); txbJahre.Clear(); txbGehalt.Clear(); txbName.Focus(); } - Seite 236 - .NET-Framework & C#.NET private void frmPraemie_Load(object sender, EventArgs e) { //Deklarationen DataGridViewCellStyle frmZahlen = new DataGridViewCellStyle(); DataGridViewCellStyle frmName = new DataGridViewCellStyle(); DataGridViewCellStyle frmHeader = new DataGridViewCellStyle(); DataGridViewTextBoxColumn clName = new DataGridViewTextBoxColumn(); DataGridViewTextBoxColumn clJahre = new DataGridViewTextBoxColumn(); DataGridViewTextBoxColumn clGehalt = new DataGridViewTextBoxColumn(); DataGridViewTextBoxColumn clPaemie = new DataGridViewTextBoxColumn(); DataGridViewTextBoxColumn clSumme = new DataGridViewTextBoxColumn(); //Formate frmZahlen.Alignment = DataGridViewContentAlignment.MiddleCenter; frmZahlen.BackColor = Color.AntiqueWhite; frmZahlen.ForeColor = Color.Chocolate; frmZahlen.Format = "#,##0.00"; frmName.Alignment = DataGridViewContentAlignment.MiddleCenter; frmName.BackColor = Color.AntiqueWhite; frmName.ForeColor = Color.Chocolate; frmName.Format = "#0"; frmHeader.Alignment = DataGridViewContentAlignment.MiddleCenter; frmHeader.BackColor = Color.Wheat; frmHeader.ForeColor = Color.Black; //Spaltenaufbau clName.DefaultCellStyle = frmName; clName.HeaderText = "Nachname"; clName.HeaderCell.Style = frmHeader; clName.Width = 100; clName.Name = "clName"; clJahre.DefaultCellStyle = frmZahlen; clJahre.HeaderText = "Dienszeit"; clJahre.HeaderCell.Style = frmHeader; clJahre.Width = 100; clJahre.Name = "clJahre"; clGehalt.DefaultCellStyle = frmZahlen; clGehalt.HeaderText = "Gehalt"; clGehalt.HeaderCell.Style = frmHeader; clGehalt.Width = 100; clGehalt.Name = "clGehalt"; - Seite 237 - .NET-Framework & C#.NET clPaemie.DefaultCellStyle = frmZahlen; clPaemie.HeaderText = "Prämie"; clPaemie.HeaderCell.Style = frmHeader; clPaemie.Width = 100; clPaemie.Name = "clPaemie"; clSumme.DefaultCellStyle = frmZahlen; clSumme.HeaderText = "Summe"; clSumme.HeaderCell.Style = frmHeader; clSumme.Width = 100; clSumme.Name = "clSumme"; //Gridaufbau grdPraemie.Columns.AddRange(clName, clJahre, clGehalt, clPaemie, clSumme); grdPraemie.RowCount = 1; grdPraemie.Width = 500 + 25; grdPraemie.RowHeadersVisible = false; grdPraemie.AllowUserToAddRows = false; grdPraemie.ReadOnly = true; grdPraemie.Visible = true; } - Seite 238 - .NET-Framework & C#.NET private void btnRechnen_Click(object sender, EventArgs e) { //Deklarationen int z, s, zeilen; double[,] aryPraemie; double prozent; //Dimension bestimmen zeilen = grdPraemie.RowCount; aryPraemie = new double[zeilen + 1, 4]; //Daten einlesen for (z = 1; z <= zeilen; z++) for (s = 1; s <= 2; s++) aryPraemie[z ‐ 1, s ‐ 1] = Convert.ToDouble (grdPraemie.Rows[z ‐ 1].Cells[s].Value); //Prämie & Zeilensumme for (z = 0; z < zeilen; z++) { if (aryPraemie[z, 0] < 1) prozent = 0.05; else if (aryPraemie[z, 0] < 5) prozent = 0.1; else if (aryPraemie[z, 0] < 10) prozent = 0.15; else prozent = 0.2; aryPraemie[z, 2] = aryPraemie[z, 1] * prozent; aryPraemie[z, 3] = aryPraemie[z, 1] + aryPraemie[z, 2]; } //Spaltensummen Gehalt, Prämie, Summe for (s = 1; s <= 3; s++) for (z = 0; z < zeilen; z++) aryPraemie[zeilen, s] = aryPraemie[zeilen, s] + aryPraemie[z, s]; //Ausgabe grdPraemie.RowCount++; for (s = 1; s <= 3; s++) for (z = 0; z <= zeilen; z++) grdPraemie.Rows[z].Cells[s + 1].Value = aryPraemie[z, s]; } - Seite 239 - .NET-Framework & C#.NET 11.4.7 Kosten- und Gewinnvergleich Bei der folgenden C#-Anwendung werden die nachstehend Daten zur Abteilung, zum Umsatz und zu den Kosten erfaßt. Es können beliebig viele Abteilungen eingegeben werden. Beim Klicken des Button „Berechnungen“ werden die relevanten Daten in eine Array eingelesen, dort die fehlende Werte berechnet und ausgegeben. Folgende Berechnungen sind durchzuführen: Umsatz / Mitarbeiter (Spalte 4 im Grid). Ermittlung der Abteilung mit dem höchsten Umsatz je Mitarbeiter (Spalte 5 im Grid). Differenz zwischen Soll- und Ist-Kosten (Spalte 8 im Grid). Ausgabe eine Warnung wenn die Abweichung negativ ist (Spalte 9 im Grid). Berechnung der Summen der Spalten 2 3, 4, 6 und 7 Bei der Ausgabe ist die Summenzeile in „Grün“ auszugeben. Die anderen Spalten sind entsprechend dem obigen ScreenShot aufzubereiten. - Seite 240 - .NET-Framework & C#.NET Überlegungen zu den Berechnungen Bei Unklarheiten sollten die Berechnung einmal per Hand als eine Alternative der Problemanalyse durchgeführt werden. Mit Hilfe des Arrays sollen Berechnungen durchgeführt werden. Damit muß das Array von einem numerischen Datentyp z.B. Double sein. Das Array muß alle Daten von der 2. Bis zur 8. Spalte aufnehmen. Die Inhalte der ersten und der letzten Spalte sind vom Typ String und daher nicht in dem Array darstellbar. Verarbeitungsschritte Einlesen der Daten vom Grid in das Array beginnend bei Spalte 2 bis Spalte 7 mit Ausnahme der Spalten 4 und 5. Berechnung des Umsatz je Mitarbeiter über alle Abteilungen durch Berechnung der Kostendifferenz über alle Abteilungen durch Die Warnung muß direkt im Grid ausgegeben werden. Für alle Abteilungen ist die Warnung auszugeben, wenn die berechnete Differenz negativ ist. Ausgabe der Wert vom Array ins Grid. Maximaler Umsatz je Mitarbeiter Hier soll die Abteilung bestimmt werden, die den maximalen Umsatz je Mitarbeiter erreicht hat. Die Vorgehensweise kann an dem folgenden Beispiel beschrieben werden. Es existiert ein Stapel mit Karten. Jede Karte ist mit einer laufenden Nummer und einem Zahlenwert versehen. Es soll jetzt aus diesem Stapel, die Karte mit der größten Zahl ermittelt werden. Führt man das per Hand durch, so wird man sich einen Zettel für Notizen zur Hand nehmen und den Stapel mit den Karten durcharbeiten. Man nimmt die erste Karte und notiert die laufende Nummer und den Wert. Dann betrachtet man die zweite Karte. Ist der Wert größer als der notierte Wert, streicht man die alten Notizen und übernimmt die neue laufende Nummer und den neuen Zahlenwert. Ist der Wert auf der Karte geringer als bleiben die alten Werte erhalten. Am Ende wird auf dem Zettel die laufende Nummer der Karte stehen, die den höchsten Zahlenwert aufwies. - Seite 241 - .NET-Framework & C#.NET Struktogramm Array und Grid aufbauen Einlesen der Daten Umsatz / Mitarbeiter Abteilung mit maximalem Umsatz je Mitarbeiter Differenz - Seite 242 - .NET-Framework & C#.NET Summe Ausgabe Warnung - Seite 243 - .NET-Framework & C#.NET Code private void frmKostenRechnung_Load(object sender, EventArgs e) { //Deklarationen DataGridViewTextBoxColumn clAbteilung = new DataGridViewTextBoxColumn(); DataGridViewTextBoxColumn clMitarbeiter = new DataGridViewTextBoxColumn(); DataGridViewTextBoxColumn clUmsatz = new DataGridViewTextBoxColumn(); DataGridViewTextBoxColumn clUmsatzMa = new DataGridViewTextBoxColumn(); … int spaltenBreite; //Aufbau der Spalten stlZahlen.Alignment = DataGridViewContentAlignment.MiddleRight; stlZahlen.Format = "#,##0.00"; spaltenBreite = 90; clAbteilung.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleLeft; clAbteilung.DefaultCellStyle.ForeColor = Color.DarkBlue; clAbteilung.HeaderText = "Abteilung"; clAbteilung.HeaderCell.Style.Alignment = DataGridViewContentAlignment.MiddleCenter; clAbteilung.Width = spaltenBreite; … clMitarbeiter.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter; clMitarbeiter.HeaderText = "Mitarbeiter"; clMitarbeiter.HeaderCell.Style.Alignment = DataGridViewContentAlignment.MiddleCenter; clMitarbeiter.Width = spaltenBreite; clUmsatz.DefaultCellStyle = stlZahlen; clUmsatz.HeaderText = "Umsatz"; clUmsatz.HeaderCell.Style.Alignment = DataGridViewContentAlignment.MiddleCenter; clUmsatz.Width = spaltenBreite; ... //Gridaufbau grdKLR.Columns.AddRange(clAbteilung, clMitarbeiter, clUmsatz, clUmsatzMa, clRanking, clKostenSoll, clKostenIst, clAbweichung, clWarnung); grdKLR.AllowUserToAddRows = false; … grdKLR.Width = grdKLR.Columns.Count * spaltenBreite + 30; } - Seite 244 - .NET-Framework & C#.NET private void btnErfassen_Click(object sender, EventArgs e) { //Deklarationen int dsn; //Prozedur grdKLR.Rows.Add(); dsn = grdKLR.Rows.Count ‐ 1; grdKLR.Rows[dsn].Cells[0].Value = txbAbteilung.Text; grdKLR.Rows[dsn].Cells[1].Value = txbMitarbeiter.Text; grdKLR.Rows[dsn].Cells[2].Value = Convert.ToDouble(txbUmsatz.Text); grdKLR.Rows[dsn].Cells[5].Value = Convert.ToDouble(txbKostenSoll.Text); grdKLR.Rows[dsn].Cells[6].Value = Convert.ToDouble(txbKostenIst.Text); } private void btnBerechnung_Click(object sender, EventArgs e) { //Deklarationen double[,] aryKLR; int anzahl, z, s, maxZeile; double maxWert; //Aufbau des Arrays & Summenzeile Grid anzahl = grdKLR.Rows.Count; aryKLR = new double[anzahl + 1, 7]; grdKLR.Rows.Add(); //Einlesen der Daten for (z = 0; z <= anzahl ‐ 1; z++) for (s = 1; s <= 6; s++) if (s != 3 & s != 4) aryKLR[z, s ‐ 1] = Convert.ToDouble (grdKLR.Rows[z].Cells[s].Value); //Umsatz / Mitarbeiter & Ranking for (z = 0; z <= anzahl ‐ 1; z++) aryKLR[z, 2] = aryKLR[z, 1] / aryKLR[z, 0]; - Seite 245 - .NET-Framework & C#.NET maxWert = 0; maxZeile = 0; for (z = 0; z <= anzahl ‐ 1; z++) if (aryKLR[z, 2] > maxWert) { maxWert = aryKLR[z, 2]; maxZeile = z; } aryKLR[maxZeile, 3] = 1; //Differenz for (z = 0; z <= anzahl ‐ 1; z++) { aryKLR[z, 6] = aryKLR[z, 4] ‐ aryKLR[z, 5]; } //Summen for (s = 0; s <= 5; s++) if (s != 3) for (z = 0; z <= anzahl ‐ 1; z++) aryKLR[anzahl, s] = aryKLR[anzahl, s] + aryKLR[z, s]; //Ausgabe grdKLR.Rows[anzahl].Cells[0].Value = "Summe"; for (z = 0; z <= anzahl; z++) for (s = 0; s <= 6; s++) { grdKLR.Rows[z].Cells[s + 1].Value = aryKLR[z, s]; if (z == anzahl) grdKLR.Rows[z].Cells[s + 1].Style.ForeColor = Color.DarkGreen; } //Warnung for (z = 0; z <= anzahl; z++) if (aryKLR[z, 6] < 0) grdKLR.Rows[z].Cells[8].Value = "Warnung"; } - Seite 246 - .NET-Framework & C#.NET 11.4.8 Break-Even-Analyse Das nachstehende C#-Programm dient der Darstellung einer Break-Even-Analyse. Dabei werden für zwei Investitionen jeweils die fixen und die variablen Kosten eingegeben. Es liegt damit eine lineare Kostenfunktion des Typs ∗ zugrunde. Die Kapazitätsgrenze ist der Wert, bis zu dem die Berechnungen durchgeführt werden; die Schrittweite legt den Zuwachs zur nächst höheren Ausbringungsmenge fest. Bei der Ausgabe soll die niedrigere der beiden Werte in Grün angegeben werden. - Seite 247 - .NET-Framework & C#.NET Struktogramm Code private void Form1_Load(object sender, EventArgs e) { //Deklarationen DataGridViewTextBoxColumn clMenge = new DataGridViewTextBoxColumn(); DataGridViewTextBoxColumn clMaschine1 = new DataGridViewTextBoxColumn(); DataGridViewTextBoxColumn clMaschine2 = new DataGridViewTextBoxColumn(); //Gridaufbau clMenge.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter; clMenge.DefaultCellStyle.Format = "#,##0"; clMenge.HeaderCell.Value = "Menge"; clMenge.HeaderCell.Style.Alignment = DataGridViewContentAlignment.MiddleCenter; clMenge.Width = 100; clMaschine1.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight; clMaschine1.DefaultCellStyle.Format = "#,##0.00 €"; clMaschine1.HeaderCell.Value = "Maschine 1"; clMaschine1.HeaderCell.Style.Alignment = DataGridViewContentAlignment.MiddleCenter; clMaschine1.Width = 150; … grdKosten.Columns.AddRange(clMenge, clMaschine1, clMaschine2); grdKosten.RowHeadersVisible = false; grdKosten.AllowUserToAddRows = false; grdKosten.AllowUserToDeleteRows = false; grdKosten.ReadOnly = true; grdKosten.Width = 430; grdKosten.Visible = false; } - Seite 248 - .NET-Framework & C#.NET private void btnBerechnungen_Click(object sender, EventArgs e) { //Deklarationen double kf1, kv1, kf2, kv2, kapazitaet, kg1, kg2; int step, menge; //Einlesen der Werte kf1 = Convert.ToDouble(txbKf_1.Text); kv1 = Convert.ToDouble(txbKv_1.Text); kf2 = Convert.ToDouble(txbKf_2.Text); kv2 = Convert.ToDouble(txbKv_2.Text); kapazitaet = Convert.ToDouble(txbMenge.Text); step = Convert.ToInt32(txbSchrittweite.Text); //Berechnung & Ausgabe grdKosten.Rows.Clear(); for (menge = 0; menge <= kapazitaet; menge = menge + step) { //Berechnungen kg1 = kv1 * menge + kf1; kg2 = kv2 * menge + kf2; //Ausgabe grdKosten.Rows.Add(); grdKosten.Rows[grdKosten.Rows.Count‐1].Cells[0].Value = menge; grdKosten.Rows[grdKosten.Rows.Count‐1].Cells[1].Value = kg1; grdKosten.Rows[grdKosten.Rows.Count‐1].Cells[2].Value = kg2; if (kg1 < kg2) grdKosten.Rows[grdKosten.Rows.Count‐1].Cells[1].Style. ForeColor = Color.DarkGreen; else grdKosten.Rows[grdKosten.Rows.Count ‐ 1].Cells[2].Style. ForeColor = Color.DarkGreen; } } - Seite 249 - .NET-Framework & C#.NET 11.4.9 Verteilung von Gemeinkosten Mit der nachstehenden Anwendung werden die Gemeinkosten für Heizung und Verwaltung auf die Abteilungen verteilt. Dabei werden die Heizkosten proportional zu Fläche der Abteilung und die Verwaltungskosten linear aufgeteilt. Mit dem Button „Erfassen“ werden die Abteilungsdaten im Grid erfaßt. Beim Klicken des Button „Berechnungen“ werden die Gemeinkosten eingelesen und die relevanten Daten aus dem Grid in ein Array übertragen. Im Array werden dann die nachstehenden Berechnungen durchgeführt und diese Werte im Grid ausgegeben. - Seite 250 - .NET-Framework & C#.NET Struktogramm Gridaufbau und Array Einlesen der Daten Summe der Fläche Verteilungsschlüssel und Verteilung Zeilensumme Ausgabe - Seite 251 - .NET-Framework & C#.NET Code private void btnBerechnung_Click(object sender, EventArgs e) { //Deklarationen double heizung, verwaltung, anteilHeizung, anteilVerwaltung; double[,] aryGMK; int anzahl, z, s; //Aufbau Arrray & Grid um Summenzeile erweitern anzahl = grdGMK.Rows.Count; aryGMK = new Double[anzahl + 1, 4]; grdGMK.Rows.Add(); //Einlesen der Daten heizung = Convert.ToDouble(txbHeizung.Text); verwaltung = Convert.ToDouble(txbVerwaltung.Text); for (z = 0; z <= anzahl ‐ 1; z++) aryGMK[z, 0] = Convert.ToDouble (grdGMK.Rows[z].Cells[1].Value); //Summe der Fläche for (z = 0; z <= anzahl ‐ 1; z++) aryGMK[anzahl, 0] = aryGMK[anzahl, 0] + aryGMK[z, 0]; //Verteilungsschlüssel anteilHeizung = heizung / aryGMK[anzahl, 0]; anteilVerwaltung = verwaltung / anzahl; //Kostenverteilung for (z = 0; z <= anzahl ‐ 1; z++) { aryGMK[z, 1] = aryGMK[z, 0] * anteilHeizung; aryGMK[z, 2] = anteilVerwaltung; } //Zeilensummen for (z = 0; z <= anzahl ‐ 1; z++) for (s = 1; s <= 2; s++) aryGMK[z, 3] = aryGMK[z, 3] + aryGMK[z, s]; //Ausgabe for (z = 0; z <= anzahl ‐ 1; z++) for (s = 1; s <= 3; s++) grdGMK.Rows[z].Cells[s + 1].Value = aryGMK[z, s]; //Ausgabe der letzten Zeile grdGMK.Rows[anzahl].Cells[1].Value = aryGMK[anzahl, 0]; grdGMK.Rows[anzahl].Cells[2].Value = heizung; grdGMK.Rows[anzahl].Cells[3].Value = verwaltung; grdGMK.Rows[anzahl].Cells[4].Value = heizung + verwaltung; - Seite 252 -