101 LINQ Beispiele fuer C# Programmierer
Wer Datenbankprogrammierung mit C# betreibt wird früher oder später nicht an LINQ vorbeikommen. Wer sich damit etwas auseinandersetzt wird schnell merken, dass diese Queries schnell recht komplex werden.
Hier bietet Mocrosofts MSDN eine tolle Beispielsammlung an, in der fast alle Anwendungsfälle beschrieben sind. Das ganze findet ihr im MSDN Visual C# Developer Center.
.NET: Projekte fuer Mobile Geraete koennen auf dem Desktop ausgefuehrt werden
Ich denke, dass viele von euch es schon längst gewusst haben, aber heute habe ich zufällig entdeckt, dass man die Projekte, die für Smartphones mit Windows Mobile programmiert wurden direkt auf dem Desktop ausführen kann.
Dabei bedarf es keinerlei Anpassung oder Modifikation des Codes. Einfach doppelklicken und ab geht's!
![]()
Bild 1: Das selbe Programm auf beiden Plattformen (Bild von Tom Wendel)
Das ist (so weit ich weiß) einzigartig in der Programmierwelt oder? Denn Java Programme können nicht direkt auf den Desktop ausgeführt werden, und genauso iPhone Apps!
Ich bin mal gespannt, wie lange es dauert bis das Ganze auch umgekehrt möglich ist!
Wirklich genial!
C#: Alle Sichtbaren Prozesse / Fenster auflisten
Immer öfter benötige ich beim erstellen einer Software Zugriff auf fremde Fenster, doch leider bietet hier die Process-Klasse des .NET Frameworks nur wenig Hilfe. Denn mit ihr kann mann nicht alle Fenster ansprechen!
Problem:
Nehmen wir mal wir möchten alle zur Zeit geöffneten Fenster in einer Liste darstellen, dabei haben wir 3 Windows Explorer Fenster, 2 Mal FireFox und 3 anderen Programme geöffnet.
Wenn wir nun auf die Mittel des .NET Frameworks zurückgreifen, müssten wir das so angehen:
foreach (Process p in Process.GetProcesses())
{
if (p.MainWindowHandle != null){
MessageBox.Show(p.MainWindowTitle + " - " + p.MainWindowHandle.ToString());
}
}
Der Code ist sehr simpel und leicht verständlich. Wir prüfen, ob ein Fenster sichtbar ist, in dem wir schauen, ob ein Handle dafür hinterlegt ist. Leider kann man das meines Wissens nicht anders lösen.
Aber wie es euch vielleicht schon aufgefallen ist benutzen wir hier die Funktion p.MainWindowHandle() - das Problem hierbei ist das kleine Wörtchen "Main", das in dem Funktionsnamen steckt, denn diese Funktion liefert uns NUR den Titel und das Fensterhandle des Hauptfensters des Programms, oder in anderen Worten, des Fensters eines Programms, das zuletzt aktiv gewesen ist.
Das bedeutet, dass wenn wir 3 Firefox Fenster offen haben wir nur das Handle und den Titel des zuletzt aktiven Fenster bekommen. Schlimmer ist es noch mit den Systemfenstern, da diese immer unter dem Prozess "Explorer" laufen, der unter anderem auch für die Darstellung der Taskleiste verantwortlich ist.
Das bedeutet, dass wir im Normalfall nicht die Windows Explorer Fenster ansprechen können sondern stattdessen das Handle der Taskleiste zurückbekommen, da diese meißt aktiver ist als die Windows Fenster und meistens auch immer im Vordergrund bleibt. (Siehe letzter Artikel)
Lösung:
Doch wie bekommen wir nun alle Fenster? Hier bietet uns das Framework leider keine Hilfe, weswegen wir auf die Win32 API zurückgreifen müssen. Hier finden wir Methoden, die uns viel über die Fenster verraten:
[DllImport("user32.dll")] //Die Position und Größe eines Fensters bestimmen
public static extern long GetWindowRect(IntPtr hwnd, ref RECT lpRect);
[DllImport("user32.dll")] //Prüfen, ob ein Fenster Sichtbar ist
public static extern bool IsWindowVisible(IntPtr hWnd);
[DllImport("user32.Dll")] //Alle offenen Fenster abrufen
public static extern int EnumWindows(ProcessListDemo.Windows.WinCallBack x, int y);
[DllImport("User32.Dll")] //Titel eines Fensters auslesen
public static extern void GetWindowText(int h, StringBuilder s, int nMaxCount);
[DllImport("User32.Dll")] //Die Klasse des Fensters besimmen
public static extern void GetClassName(int h, StringBuilder s, int nMaxCount);
Die wichtigsten hier sind "EnumWindows" und "IsWindowVisible". Die erste liefert uns eine Liste mit allen Fensterhandles die zur Zeit aktiv sind und mit der Zweiten können wir bestimmen, ob ein Fenster sichtbar ist oder nicht. Die anderen Funktionen lassen wir erstmal ungeachtet.
Wie eben schon erwähnt benutzen wir die EnumWindows-Funktion um uns alle Fensterhandles zu besorgen. Diese Funktion arbeitet hierbei über einen Delegaten Aufruf.
///
/// Beinhaltet alle zur Zeit geöffneten und Minimierten Fenster
///
public LinkedList lstWindows { get; set; }
///
/// Delegate Funktion für EnumWindows (Siehe Declarations)
/// Gibt die Werte an EnumWindowCallBack weiter
///
public delegate bool WinCallBack(int hwnd, int lParam);
private void getWindows()
{
//Liste mit Fenstern befüllen
ProcessListDemo.Declarations.EnumWindows(new WinCallBack(EnumWindowCallBack), 0);
}
///
/// Diese Funktion wird durch die Delegate Funktion WinCallBack aufgerufen
/// und iteriert durch alle zur Zeit geöffneten Fenster
private bool EnumWindowCallBack(int hwnd, int lParam)
{
IntPtr windowHandle = (IntPtr)hwnd;
StringBuilder sb = new StringBuilder(1024);
StringBuilder sbc = new StringBuilder(256);
ProcessListDemo.Declarations.GetClassName(hwnd, sbc, sbc.Capacity);
ProcessListDemo.Declarations.GetWindowText((int)windowHandle, sb, sb.Capacity);
//Nur Prozesse mit einer Beschreibung, also einem Fenster bearbeiten
if (sb.Length > 0)
{
ProcessListDemo.Declarations.RECT r = new ProcessListDemo.Declarations.RECT(); //Fensterposition & Größe bestimmen:
ProcessListDemo.Declarations.GetWindowRect(windowHandle,ref r);
Window w = new Window( sb + "",
windowHandle,
sbc + "",
ProcessListDemo.Declarations.IsWindowVisible(windowHandle),
new ProcessListDemo.Declarations.Point(r.Left, r.Top),
new ProcessListDemo.Declarations.Point(r.Right - r.Left, r.Bottom - r.Top),
Window.WinType.Normal);
this.lstWindows.AddLast(w);
}
return true;
}
In einfachen Worten erklärt passiert hier folgendes: Wir rufen die EnumWindows Funktion auf und übergeben dieser als Parameter die Referenz auf die Funktion EnumWindowCallBack, dazu benötigen wir die Delegate Funktion WinCallBack. Wichtig hierbei ist, dass alle Funktionen die gleichen Parameterdefinitionen haben. Der zweite Parameter ist bei mir hier aber ungenutzt, dieser ist optional vorhanden, um zB. weitere Referenzen zu übergeben wie zB. eine Listbox worin die Ergebnisse gespeichert werden sollen. Da wir hier aber die Ergebnisse direkt in die Klassen-variable schreiben benötigen wir diese nicht.
Nachdem die EnumWindows Funktion nun aufgerufen wurde macht sie nichts anderes, als die ihr übergebene Funktion (EnumWindowCallBack) aufzurufen. Diese wird dabei für jeden Prozess einmal aufgerufen und bekommt als Parameter das Handle des Fensters.
Im Prinzip nicht kompliziert. Ich habe hier, um das ganze besser zu visualisieren zwei Klassen namens "Window" und "Windows" erstellt. Diese übernehmen die ganze Arbeit für euch und erstellen eine Komplette Übersicht aller Fenster inklusive der Angaben, wie Größe, Position, Handle und Titel. Diese könnt ihr gern in euren eigenen Projekten nutzen.
Bild 1: Die Eigenschaften der Window-Klasse
Wenn ihr euch mal die Ergebnisse der EnumWindows Funktion anschaut werdet ihr feststellen, dass es ziemlich viele Fenster sind die da so im Hintergrund laufen, aber unsichtbar sind! Um diese Fenster zu filtern benutzen wir die Funktion IsWindowVisible und prüfen ob das Fenster Sichtbar ist oder nicht.
Bild 2: Das Demoprogramm in Aktion, zeigt alle Fensterprozesse
In dem Demoprogramm zeige ich euch wie ihr die zwei Klassen "Window" und "Windows" sehr einfach dazu benutzen könne, um eine Komplette Übersicht über alle Fenster des Systems zu bekommen.
private void cmdList_Click(object sender, EventArgs e)
{
//Alte Liste Leeren
lstProcess.Items.Clear();
//Alle vorhandenen Fenster bestimmen
Windows windows = new Windows();
//Alle Fenster durchgehen und in die Lite einsetzen
foreach (Window w in windows.lstWindows)
{
ListViewItem lvi = new ListViewItem(w.winTitle);
lvi.SubItems.AddRange(new string[] { w.winClass,
w.winHandle.ToString(), w.winVisible.ToString() });
lstProcess.Items.Add(lvi);
}
}
Wie man sieht ist diese Angelegenheit dank der "Windows"-Klassen nun sehr einfach geworden. Zum besseren Verständnis solltet ihr euch das Demoprojekt herunterladen.
Download des Demoprojekts: Download [VS 2008 C#]
Wie hat euch dieser Artikel gefallen? Habt ihr Verbesserungsvorschläge, Kritik oder Lob? Bitte ein Kommentar schreiben!
.NET: Windows Taskleiste verstecken
In den letzten Tagen ist mir durch einen Zufall aufgefallen, dass die Windows Taskleiste (seit Windows Vista) in einem Fenster Prozess des Explorers läuft.
Das interessante/lustige hierbei ist, dass die Taskleiste als Fenster erkannt wird und dementsprechend auch als Fenster behandelt werden kann. Also können wir sämtliche Funktionen für Fenster auch auf die Taskleiste anwenden.
Als Beispiel blende ich hier die Taskleiste mit Hilfe der ShowWindow Funktion aus. Das lustige hierbei, ist dass nicht die Ganze Taskleiste von dieser Aktion betroffen ist. Der "Start"-Knopf von Windows bleibt weiterhin sichtbar und funktioniert, nur das Drumherum ist nun verschwunden.
Der Prozess den wir suchen läuft als "explorer" und sollte der einzige Prozess sein, der ein MainWindowHandle hat aber keinen MainWindowTitle. Wenn man diese zwei Kriterien anwendet, kann man ganz einfach diesen Prozess isolieren:
[DllImport("user32.dll")]
public static extern long ShowWindow(IntPtr hWnd, int nCmdShow);
private IntPtr tbHandle = IntPtr.Zero;
private void button1_Click(object sender, EventArgs e)
{
Process[] pr = Process.GetProcesses();
foreach (Process p in pr)
{
if (p.MainWindowHandle != null && p.MainWindowTitle == ""
&& p.ProcessName == "explorer")
{
tbHandle = p.MainWindowHandle;
}
}
if (tbHandle != IntPtr.Zero)
{
ShowWindow(tbHandle, 0);
}
else
{
MessageBox.Show(this, "Konnte Prozess nicht finden!",
"Fehler", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
}
Da man nun das MainWindowHandle hat kann man nun mit Hilfe der ShowWindow-Funktion aus der Win32 API das Fenster verstecken.
WICHTIG: Bitte vor dem Verstecken der Taskleiste unbedingt das MainWindowHandle abspeichern, da man diese sonst nicht wieder einblenden kann!
Wenn man die Aktion erfolgreich ausführt sieht man folgendes:
Bild 1: Die Taskleiste ist verschwunden, nur der Start-Knopf ist noch da
Wie man sieht ist nur noch der Start-Knopf da und die gesamte Taskleiste ist verschwunden und ist auch nicht anklickbar!
Wenn man die Option "Taskleiste Automatisch ausblenden" aktiviert hat hat man sogar einen noch schöneren Effekt!
Also wenn ihr nicht wollt, dass euch jemand auf die Taskleiste glotzt oder ihr jemandem einen kleinen Streich spielen wollt könnt ihr das ja mal testen!
Falls ihr eure Taskleiste versteckt habt und aus versehen das Programm beendet könnt ihr die Taskleiste nicht mehr über das Programm wiederherstellen! Die einzige Lösung ist es im Taskmanager ([STRG]+[SHIFT]+[ESC]) den Prozess "explorer.exe" zu beenden und dann über Datei->Neuer Task->"explorer"->[ENTER] den Explorer neu zustarten.
Ich hoffe diese kleine Spielerei hat euch gefallen, das Demo Projekt (diesmal in C#) gibts hier:
Demoprojekt: Download [VS 2008]
Interessantes aus der Java Welt Teil 2
In diesem Artikel möchte ich kurz was über statische Objekte in Java erzählen. Das ist ein sehr interessantes Thema, dass oft zu unerwarteten Fehlern führen kann.
Ich möchte hier zunächst mit einem kleinem Beispiel anfangen. Lest euch diesen kurzen Code durch und schaut mal ob ihr sagen könnt ob dieser kompiliert werden kann, wenn nein warum nicht und wenn ja was kommt raus?
Ernsthaft, nehmt euch eine Minute Zeit:
public class Demo {
static String text = "Ich bin die Klasse Demo";
public Demo getInstance(){
System.out.println("Ich bin die Methode");
return null;
}
public static void main(String [] args){
System.out.println(new Demo().getInstance().text);
}
}
Lasst uns den Code mal gemeinsam durchgehen. Wir deklarieren eine statische Klassenvariable vom Typ String und initialisieren diese auch gleich, desweiteren haben wir eine Methode getInstance() die einen Text auf der Konsole ausgibt und dann den Wert null zurückgibt!
Als letztes folgt die main()-Methode die das Programm ausführt, schauen wir uns diese etwas genauer an, denn hier ist der interessante Teil!
In der Main()-Methode wird eine Instanz der eigenen Klasse angelegt und dann die Funktion getInstance() ausgeführt, soweit alles ok, aber nun gibt die getInstance-Methode null als Rückgabewert zurück, also wird hier eine komplett "leere" Klasse zurückgegeben, und aus dieser "leeren" Klasse lesen wir nun die Variable text aus und geben diese auf Der Konsole aus.
Kann das Funktionieren? Kann ich eine Variable aus einer nicht instanzierten "leeren" Klasse benutzen? - Ja das können wir. Dementsprechend erhalten wir folgendes im Konsolen Fenster:
Ich bin die Methode Ich bin die Klasse Demo
Doch warum ist das so? Dazu muss man wissen, dass es so etwas wie das Klasseninventar und Objektinventar gibt. Alle Statischen Objekte gehören zum Klasseninventar und alle nicht statischen zum Objektinventar.
Wo ist der Unterschied? Worin unterscheidet sich eine Klasse von einem Objekt? - Ein Objekt entsteht aus einer Klasse, daher kann es immer nur eine einzige Klasse geben, aber mehrere Objekte.
Schauen wir unsere Demo-Klasse mal an. Wir können beliebig viele Demo-Objekte aus der Demo-Klasse erstellen aber die Klasse selbst bleibt einzigartig.
Und genau das selbe geschieht auch mit den Objekten des Klasseninventars, alle diese Objekte sind nur ein einziges Mal vorhanden! Das heist, auch wenn man 100 Objekte vom Typ Demo anlegt hat man trotzdem nur eine einzige text-Variable! - Man braucht eine Weile um das zu schlucken, das gebe ich zu!
Aber vielleicht wird es etwas ersichtlicher an einem Beispiel. Nehmen wir an, wir programmieren mit Java eine Besucherzähler Klasse. Diese Klasse wird jedes Mal erzeugt wenn ein Benutzer eine Webseite aufruft und erhöht den Wert einer Zähler Variable um 1.
Da aber jeder Besucher seine eigene Instanz der Klasse bildet hat jeder Benutzer sein eigenes Besucherzähler Objekt. Wenn die Variable, die für das Zählen der Besucher zuständig ist nicht Statisch ist, hat jeder Benutzer eine neue - eigene - Variable die erhöht wird, und wenn mehrere Benutzer zur selben Zeit auf der Seite sind erhöhen Sie NUR ihre eigene Variable aus dem Objektinventar und nicht die allgemeine Variable.
Man muss hier also die Zähler Variable statisch machen, damit alle Objekte, egal wie viele es sind, immer auf die selbe Variable zugreifen, nämlich die aus dem Klasseninventar!
Kommen wir zurück auf das obige Beispiel, denn dieses funktioniert nur, da die text-Variable Statisch ist und somit im Klasseninventar liegt. Entfernt man das Wörtchen "static" vor der Definition, wird das Programm mit einer NullPointerException enden:
Ich bin die Methode Exception in thread "main" java.lang.NullPointerException at Twitter.Demo.main(Demo.java:11)
Denn nun liegt die text-Variable im Objektinventar und da das Objekt mit null angegeben ist, also "leer" ist endet der Aufruf in einer Exception.
Soviel dazu, ich hoffe diese kleine Theoriestunde hat euch gefallen. Ich würde mich über Feedback (und evtl. Verbesserungen) freuen, wollt ihr zukünftig mehr solcher Themen hier haben?
VB.NET: FitzBox IP erneuern ueber uPnP
Die FritzBox ist als Router weit verbreitet und bietet einen Haufen an Konfigurationsmöglichkeiten an. Eins der nützlichsten Features ist uPnP (Universal Plug and Play). Diese Schnittstelle bietet uns eine sehr bequeme Möglichkeit mit dem Gerät zu kommunizieren ohne dass man einen Benutzernamen oder ein Kennwort benötigt!
Wer öfter mal im Internet unterwegs ist, kennst sicherlich mehrere gute Gründe seine IP zu wechseln. Und das ist sehr einfach, denn alles was dafür nötig ist, ist eine erneute Einwahl ins Internet.
Dies kann man sehr einfach über die Benutzeroberfläche der FritzBox machen oder einfach "oldschool"-mäßig das Netzwerkkabel aus der FritzBox ziehen und wieder einstecken. (Letzteres erfordert ebenfalls keinen Benutzernamen und Passwort)
Doch wenn man des öfteren auf diese Funktionalität angewiesen ist, ist es doch relativ nervig und umständlich. Deswegen werden wir hier ein einfaches kleines Programm entwickeln, dass für uns den Router zu einer Neueinwahl ins Internet "zwingt".
Wie oben bereits erwöhnt heißt die Technologie dafür UPnP (Universal Plug and Play). Über diese Technologie lassen sich sehr viele Befehle an die Fritzbox senden, vorausgesetzt, man befindet sich in dem selben Netzwerk.
Von Statusabfragen über Auslastungen und Übertragung, lassen sich sogar Telefonnummern anwählen und Anrufe steuern, im Prinzip kann man alle Funktionen darüber ansteuern. Hier gibts eine nette Übersicht mit vielen Beispielen.
Wie werden die Anfragen eigentlich an die Fritzbox übertragen? Das geschieht sehr einfach über einen POST Aufruf, denn auf der Fritzbox (und auch auf den meisten anderen Routern) läuft ein kleiner Webserver denn man ganz einfach über den Browser erreicht, wenn man die adresse "fritz.box" in die Adresszeile tippt.
Dort ist die Fritzbox genauso aufgebaut wie eine gewöhnliche Webseite. Und diese nimmt auch POST und GET aufrufe entgegen. Genau hier setzen wir an und werden unsere Befehle rüber schicken.
Dim client As New TcpClient
client.Connect("fritz.box", 49000)
Dim stream As NetworkStream = client.GetStream
Dim bytes As Byte() = New Byte((My.Resources.msg.Length)) {}
bytes = Encoding.ASCII.GetBytes(My.Resources.msg)
stream.Write(bytes, 0, bytes.Length)
bytes = New Byte(1024) {}
Dim str As String = String.Empty
Dim count As Integer = stream.Read(bytes, 0, bytes.Length)
str = Encoding.ASCII.GetString(bytes, 0, count)
stream.Close()
client.Close()
Der Code ist sehr simpel, wir erstellen uns einen WebClient und verbinden uns mit der FritzBox. Nach der Verbindung senden wir ein POST Request raus und lesen anschließend die Antwort wieder aus.
Mit dem obigen Code senden wir folgenden Befehl an die Fritzbox:
POST /upnp/control/WANIPConn1 HTTP/1.1
HOST: fritz.box:49000
SOAPACTION: "urn:schemas-upnp-org:service:WANIPConnection:1#ForceTermination"
CONTENT-TYPE: text/xml ; charset="utf-8"
Content-Length: 293
<?xml version="1.0" encoding="utf-8"?>
<s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<u:ForceTermination xmlns:u="urn:schemas-upnp-org:service:WANIPConnection:1" />
</s:Body>
</s:Envelope>
Wie man sieht ist der Befehl ein gewöhnlicher POST Aufruf inkl. Header. Dieser übergibt einen Befehl urn:schemas-"upnp-org:service:WANIPConnection:1#ForceTermination", der der Fritzbox sagt die Verbindung ins Internet neu aufzubauen.
Man muss hierbei sehr aufpassen, besonders die Content-Length Angabe muss genaustens passen, da sonst ein Fehler als Antwort eintrudelt.
Wie immer gibts auch eine kleine Demoanwendung.
Download hier: Download [VS 2008 Projekt]
Google Buzz – braucht man es?
Gestern Abend hat Google seinen neuen Dienst Buzz vorgestellt, damit will Google wohl Facebook und Twitter einholen und eine eigene Update Community aufbauen. Und da hat Buzz wirklich potenzial!
Denn Google integriert Buzz direkt in Google Mail, somit hat jeder GMail Benutzer automatisch Buzz und muss sich nicht extra registrieren. Desweiteren wählt Google einen etwas anderen Ansatz und versucht eine Art Mischung zwischen Facebook und Twitter zu schaffen.
Das sieht man schon daran, wie die "Buzzes" (oder was auch immer die Mehrzahl von Buzz ist) kommentiert werden, das sieht genauso aus wie Bei Facebook, sogar der "Gefällt mir" Button ist vorhanden. (Siehe Bild)
Bild 1: links Buzz und rechts Facebook
Das ist ein sehr interessanter Ansatz, so ist es zum Beispiel viel bequemer etwas zu kommentieren als bei Twitter, wo man dazu einen komplett neuen Tweet erstellen muss und total die Übersicht verliert, wenn inzwischen schon ein paar neue Tweets eingegangen sind.
Die Status updates bei Buzz sind wie auch bei Facebook nicht auf 140 Zeichen begrenzt und können Bilder und auch Videos enthalten, was die Sache nochmal interessanter macht.
Was mir jedoch am besten gefällt ist, dass man deine Updates entweder Öffentlich (Für jeden einsehbar) oder Privat (nur für Freunde) freigeben kann dazu kommt noch, dass man - dank der GMail Integration - die Freunde automatisch per Mail benachrichtigen kann.
Wie auch bei Twitter lässt sich auch die aktuelle Position (Koordinaten) mit einem Buzz verbinden, sodass man die schöne eingebaute Google Maps karte benutzen kann um zu sehen wo sich die Person gerade befindet. Dies bietet Twitter leider nicht von Haus aus an.
Leider kann man zur zeit nur über das Handy Buzzen, die Freischaltung für Google Mail erfolgt im Verlauf der nächsten Tage. Dann wird es auch sicherlich noch mal einen gewaltigen Schub an Nutzern bekommen. Mich eingeschlossen.
Auf einigen News Seiten, die schon über Buzz berichtet haben sieht man auch schon die typischen Google Kommentare die darauf "hinweisen", dass Google nur auf unsere Daten aus ist. Aber ich denke jemand, der Google Mail nutzt wird dies auch verkraften können
Ich denke Google ist hier auf einem gutem Weg, und ich werde Buzz sicherlich im Auge behalten. Wenn ihr mit mir Buzzen wollt könnt ihr mich gern adden unter bigbasti[at]gmail.com.
Was meint ihr? Ist Buzz was für euch, oder bleibt ihr bei Twitter?
Links:
http://buzz.google.com
Tutorial: Model-View-Controller (MVC) Struktur in Java Projekten nutzen
Die MVC-Architektur erfreut sich in letzter Zeit sehr hoher Beliebtheit, ständig hört man über neue Frameworks die auf diese Architektur schwören. (Beispiele: Spring Framework, ASP.NET MVC, Objective C...)
Bild 1: Der Aufbau - Quelle: Wikipedia
Doch was steckt eigentlich dahinter und warum sollte man seine Struktur überdenken?
Ich denke jeder, der eine Anwendung geschrieben hat schon die Erfahrungen gemacht, dass der Code immer unübersichtlicher wird, je größer ein Projekt wird.
Hier setzt MVC an, denn durch die strickte Teilung von Präsentation (View), der Programmlogik (Controller) und der Datenschicht (Model) erhöht sich die Lesbarkeit und Wartbarkeit des Codes. So kann man ein Projekt viel einfacher um weitere Funktionen ergänzen ohne den halben Sourcecode durchzugucken.
In diesem Artikel möchte ich diese Architektur an einem kleinem Java Beispiel demostrieren. Das Programm ist natürlich nicht wirklich zu gebrauchen, es soll lediglich das Vorgehen nahelegen.
Wie bereits oben erwähnt soll die Präsentation, also das was der Benutzer zu sehen bekommt (üblicherweise das Formular, also die GUI) von der Logik getrennt werden. Deshalb dürfen in der View-Klasse nur Sachen stehen, die der Darstellung der Elemente dienen. Das was passiert wenn man eins dieser Elemente anklickt wird dann über den Controller gesteuert.
Die Berechnungen an sich stehen dann im Model, wo auch alle Objekte verweilen, die unser Programm nutzt.
Unser Demo Programm ist sehr einfach aufgebaut, wir haben nur vier Klassen:
Bild 2: Der Aufbau des Projekts
Bevor ihr euch wundert, das Programm soll uns später die Quadratwurzel einer Zahl berechnen.
An Bild 1 könnt ihr erkennen, dass die Controller Klasse die wichtigste ist, da sie eigentlich das Ganze Programm steuert und dafür sorgt, dass die View und das Model sich verständigen können. Deswegen muss die Controller Klasse die anderen Klassen kennen, die anderen brauchen sich gegenseitig aber nicht!
public class Main {
static WurzelController controller;
/**
* Diese Klasse wird nur dazu benutzt alle nötigen
* Komponenten zu Initialisieren und die erste
* View anzuzeigen
*/
public static void main(String [] args){
controller = new WurzelController();
controller.showView();
}
}
Die Klasse Main macht hier auch nichts anderes, als die anderen Klassen zu instanzieren und uns die View anzuzeigen.
An den Konstruktoren kann man auch die Abhängigkeiten erkennen. Eigentlich macht man der View auch das Model bekannt (siehe Bild 1), aber da unser Beispiel zu simpel ist können wir uns diese Bekanntschaft sparen.
Das Model ist ebenfalls sehr einfach aufgebaut, es enthält die nötigen Rechenoperationen die für unser Programm wichtig sind und bietet öffentliche Methoden mit denen der Controller die Werte abfragen kann
/**
* Das Model ist komplett unabhängig von den anderen
* Klassen und weiß nicht was um ihn herum geschieht.
* Es ist völlig egal ob man dieses Model aus einem
* Fenster oder einer Konsolen Eingabe verwendet -
* beiden würde funktionieren.
*/
public class WurzelModel {
long _value;
public WurzelModel(){
zurückSetzen();
}
public void zurückSetzen(){
this._value = 0;
}
public void berechneWurzel(long wert){
this._value = (wert * wert);
}
public long getWurzel(){
return this._value;
}
}
Wichtig hierbei ist, dass diese Klasse keine Beziehungen zu den anderen Klassen hat! Man muss sie so aufbauen, dass man sie ohne eine Änderung in einem anderen Projekt benutzen könnte.
Unsere View ist ganz typisch aufgebaut. Es werden die Steuerelemente initialisiert und auf der JForm plaziert, desweiteren muss die View Methoden bieten, mit denen man die ActionListener für die auf dem Formular liegenden Steuerelemente setzen kann. Über diese wird unser Controller mit der View kommunizieren. Dazu kommen noch die getter und setter Methoden für die Textfelder, diese werden benötigt, damit man aus dem Controller Zugriff darauf hat!
/* Die View-Klasse diese Enthält nur die Präsentation
* hier sollte man keinerlei Programmlogik finden
* alle Berechnungen und Reaktionen auf Benutzeraktionen
* sollten allesammt im Controller stehen
*/
public class WurzelView extends JFrame{
private JLabel lbl1 = new JLabel("Eingabe: ");
private JTextField txtEingabe = new JTextField(3);
private JButton cmdCalc = new JButton("Wurzen Berechnen >");
private JTextField txtErg = new JTextField(5);
private JButton cmdClear = new JButton("Zurüclsetzen");
public WurzelView(){
super("Wurzel Berechnen");
initForm();
}
/**
* Die JForm initialisieren und alle Steuerelemente
* darauf positionieren
*/
private void initForm(){
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLayout(new FlowLayout());
this.setBounds(200, 200, 500, 100);
this.add(lbl1);
this.add(txtEingabe);
this.add(cmdCalc);
this.add(txtErg);
this.add(cmdClear);
}
public void resetView(){
this.txtEingabe.setText("");
this.txtErg.setText("");
}
public String getEingabe(){
return this.txtEingabe.getText();
}
public void setErgebnis(String erg){
this.txtErg.setText(erg);
}
/**
* Funktionen bereitstellen, mit denen man später aus
* dem Controller die nötigen Listener hinzufügen kann
*/
public void setWurzelBerechnenListener(ActionListener l){
this.cmdCalc.addActionListener(l);
}
public void setResetFormListener(ActionListener l){
this.cmdClear.addActionListener(l);
}
}
Bleibt nur noch der Controller. Dieser ist auch sehr simpel aufgebaut:
/**
* Der Controller muss beide die View und das Model kennen
* da dieser für die Kommunikation zwischen den Beiden sorgt
*/
public class WurzelController {
private WurzelView _view;
private WurzelModel _model;
public WurzelController(){
this._model = new WurzelModel();
this._view = new WurzelView;
addListener();
}</pre>
<pre>
<div id="_mcePaste"> public void showView(){</div>
<div id="_mcePaste"> this._view.setVisible(true);</div>
<div id="_mcePaste"> }</div>
/**
* Die Listener, die wir aus den Internen Klassen generieren
* werden der View bekannt gemacht, sodass diese mit
* uns (dem Controller) kommunizieren kann
*/
private void addListener(){
this._view.setWurzelBerechnenListener(new WurzelBerechnenListener());
this._view.setResetFormListener(new ResetFormListener());
}
/**
* Inneren Listener Klassen implementieren das Interface ActionListener
*
* 1: Hier wird erst der eingegebene Wert aus der View geholt
* 2: Der Wert wird dem Model übergeben und die Wurzel berechnet
* 3: Die berechnete Wurzel wird aus dem Model geladen und
* 4: Wieder der View zum Darstellen übergeben
*
* ACHTUNG: Fehlerprüfung muss noch implementeirt werden
*/
class WurzelBerechnenListener implements ActionListener{
public void actionPerformed(ActionEvent e) {
long wert = Long.valueOf(_view.getEingabe());
_model.berechneWurzel(wert);
_view.setErgebnis(String.valueOf(_model.getWurzel()));
}
}
/**
* Hier wird dem View und dem Model gesagt ihre gespeicherten
* Werte zu löschen.
*/
class ResetFormListener implements ActionListener{
public void actionPerformed(ActionEvent e) {
_view.resetView();
_model.zurückSetzen();
}
}
}
Wie man sieht werden hier nur die dem Konstruktor übergebenen Referenzen auf die View und das Model gespeichert und dann die Erzeugten ActionListener der View übergeben.
Die ActionListener sind interne Klassen die nun automatisch von unserer View aufgerufen werden, wenn der Benutzer einen der Buttons klickt! Praktisch oder?
Wenn man die WurzelBerechnenListener Klasse anschaut kann man auch die Typische Kommunikation zwischen den Schichten sehen. Die View lößt ein Event aus, für dessen Abhandlung der Controller verantwortlich ist. Nun holt der Controller sich alle nötigen Daten aus der View (in diesem Fall ist es nur ein Wert, die Eingabe) und lässt das Model das Quadrat berechnen. Schließlich holt der Controller sich die berechneten Daten zurück und lässt die View diese anzeigen.
Im Grunde gar nicht kompliziert oder? So sieht das Fenster zur Laufzeit aus:
Bild 3: Das Programm zur Laufzeit
Wenn man ein neues Projekt anfängt sollte man sich natürlich erst einmal genau überlegen ob man die MVC Architektur benutzt, denn diese ist bei kleinen Projekten mit einem höheren Aufwand verbunden. Wenn man aber weiß, dass in absehbarer Zeit an dem Programm weitere Änderungen oder Erweiterungen vorgenommen werden sollte man MVC in Betracht ziehen!
ACHTUNG: Habe eben erst gemerkt, dass ich überall "Wurzel" geschrieben habe, das ergibt natürlich gar keinen Sinn!
oh mann, muss wohl sehr verwirrt gewesen sein! Quadrat müsste es natürlich heißen.
Keine Lust das nun alles nochmal zu ändern!
Die Sourcen könnt ihr hier laden: Download
iPad – Apple’s neues Produkt – Mein Eindruck
Nun kann die Welt endlich wieder ruhig schlafen, Apple hat ihr neues Gerät vorgestellt - das iPad. Dieses soll die Lücke zwischen iPhone/iPod und dem Macbook schließen.
Quelle: gdgt.com <- Mehr Bilder
Ich persönlich war auch schon gespannt auf das lang erwartete "Tablet", die Medien überschlugen sich, jeden Tag neue Gerüchte immer wildere Photoshopkreationen.
Nun ist es da, und ich muss ehrlich sagen, ich bin enttäuscht. Optisch ist das Gerät, das so ähnlich aussieht wie der Bildschirm von einem Allu-Macbook, sehr chic - wie erwartet, aber alles in einem kann man es als einen großen iPod bezeichnen.
Nun darf man aber nicht, wie bei Apple Geräten üblich, daher kommen und das iPad mit anderen Tablet PCs vergleichen. Das wäre dann der berühmte Äpfel mit Birnen vergleich.
Ich will erst einmal ausführen, was mir gefallen hat. Das iPad ist ein rundum schönes Gerät, Apple sagt selber es soll primär für "Browsing, Email, Photos, Videos, Musik, Games & eBooks" gut sein. Und nach der Keynote weis ich eins, dafür ist dieses Gerät wie gemacht.
Es kommt mir der vom iPhone und iPod bekannten Benutzeroberfläche daher, die an den größeren Bildschirm angepasst wurde und um einige neue Funktionen ergänzt wurde wie zB. PopUp Menüs.
Hut ab, das hat Apple echt drauf, die Bedienung ist super gelungen, ich als iPhone & Macbook Besitzer weiß das echt zu schätzen! Die Mail und Kalender App wurde von Grund auf überarbeitet und sieht richtig chic aus!
Ein weiteres Feature, dass wohl am wichtigsten ist, ist die Kompatibilität zu den iPhone Apps, denn man kann alle jeztschon verfügbaren Apps installieren und in voller Auflösung genießen. Desweiteren wird das iPad wohl ein starker Konkurent zu dem Kindle von Amazon werden, da das eBook Programm einfach nur grandios aussieht!
Dazu kommt noch, dass Apple eine Akkulaufzeit von 10 Stunden angibt, das ist beeindruckend!
Doch leider gibts auch Schattenseiten. Denn das iPad kommt wie auch das iPhone mit dem Safari Mobile daher, das bedeutet, dass man weiterhin keine Flash Unterstützung hat und nur YouTube Videos anschauen kann (über ein Extra Programm). Warum nur? Dieses Gerät schreit einfach danach! Wenn ich allein an die vielen Flash-basierenden Browsergames denke! Gut man kann natürlich argumentieren dass es im Appstore 140.000 Programme & Spiele gibt aber Flash ist heute (leider) immer noch eine der wichtigsten Web Technologien.
Desweiteren kann man keine Dateien herunterladen und auch keine hochladen, was man zwar nicht oft benötigt aber es dann bitter ist wenn man es mal braucht!
Weiter fällt auf, dass das iPad "nur" einen Dockconnector Port an der Unterseite hat und einen Kopfhörerstecker - exakt die selben Anschlüsse wie auf dem iPhone, inklusive der lauter/leiser Tasten und dem Stummknopf.
Warum findet man hier keinen USB-Stecker? Dick genug ist die Seite des iPads (glaube ich) oder wenigstens ein SD-Karten Slot. Diesen kann man zwar mit einem Adapter nachrüsten aber das ist doch Käse!
Ein weiteres Manko ist, dass es kein "richtiges" Betriebssystem hat. Das iPad OS (?) ist wie auch das iPhone nicht in der Lage mehrere Applikationen zur gleichen Zeit auszuführen (Multitasking). Wobei man diesen Punkt auch als Vorteil sehen kann, da das Gerät dadurch schneller und einfacher zu bedienen ist.
Genau aus diesem Grund kann man das Gerät auch nicht mit anderen Tablets vergleichen, da diese mit Windows - einem "vollen" Betriebssystem - laufen.
Leider ist genau hier auch der Nachteil der Windows Tablets, denn ein angepasstes System ist natürlich viel effizienter und einfacher. Doch hat Apple hier wiedereinmal seine Sperrvorrichtungen aufgefahren und unterbietet jegliche Zugriffe auf das Dateisystem, was bedeutet, dass man auch das iPad erst "jailbraken" muss bevor man es "vernünftig" benutzen kann!
Das Günstigste Model kostet 499 Dollar (also ca 499 Euro im Apple Wechselkurs) und kann nur 16 GB Speicher bieten und hat dazu noch kein 3G Modul integriert! Hier könnte man natürlich wieder sagen man bekommt ein gutes Netbook für das Geld - aber das wären wieder Äpfel und Birnen.
Apple hat den Zweck des iPads definiert und man muss als Kunde damit leben. Man bekommt nicht mehr und nicht weniger!
Mein Eindruck ist, dass Apple hier einen großen iPod Touch mit 16 GB Speicher für $500 verkauft. Im Vergleich zu der iPhone Präsentation verspüre ich keinerlei Begeisterung für das Produkt eher im Gegenteil. Aber vielleicht muss man nur eine Weile warten, bis die 2te Version des iPad herauskommt und alles besser macht, wie einst beim iPhone!
Interessantes aus der Java Welt Teil 1
In diesem Beitrag möchte ich mal auf ein paar Besonderheiten eingehen, denen man wohl nicht jeden Tag beim Programmieren begegnet und die teilweise auch anders arbeiten, als wie man im Kopf denkt!
Ich möchte hier mal mit einem kleinem Beispiel anfangen. Guckt euch mal den kurzen Quellcode hier an und versucht zu berechnen was nach der Ausführung des Codes auf dem Bildschirm ausgegeben wird, bzw. lässt sich dieser Code überhaupt kompilieren?
public class Main {
public static void main(String[] args) {
int a = 2;
int b = 3;
int c = a+++b;
System.out.println(c);
}
}
Kompilieren lässt es sich aber was wird nun ausgegeben? Was passiert wenn man ein dreifaches Plus benutzt?
Naja das Ergebnis ist in jedem Fall 5. Doch um zu erfahren warum das so ist, muss man ersteinmal wissen, was der Kompiler da eigentlich macht, denn wir haben 2 Möglichkeiten die ausgeführt werden können:
int c = a_+_++b; //1: Präfix Inkrement ( _ soll ein Leerzeichen darstellen)
int c = a++_+_b; //2: Postfix Inkrement
Beide Rechenwege existieren doch nur einer wird ausgeführt, nämlich der 2te, denn nur der liefert als Ergebnis 5 zurück! Führt man den ersten Rechenweg aus erhält man 6 als Ergebnis!
Wenn der Kompiler diese Zeile liest und das Plus nach dem a gelesen hat erwartet er nun eigentlich den zweiten Summanden findet aber ein weiteres Plus, so wird erstmal die a++ Anweisung ausgeführt und anschließend + b dazu gerechnet.
Warum ist das so? Eigentlich wird doch in beiden Rechenwegen eine der Variablen um 1 (durch das ++ inkrement) erhöht, oder etwa nicht? Betrachten wir dazu dieses kleine Beispiel:
public static void test(){
int a = 2;
a = ++a;
int b = 2;
b = b++;
System.out.println(a); //Ergibt 3
System.out.println(b); //Ergibt 2
}
Im Falle von a wird der Wert von a erst erhöht und dann zugewiesen, dafür sorgt das so genannte Präfix (++a) da die Pluse auf der linken Seite stehen. Bei b wird erst der Wert von b zugewiesen und dann erhöht. Dadurch dass der Wert aber schon zugewiesen wurde verfällt diese Erhöhung wieder. Wenn die Operatoren auf der rechten Seite stehen nennt man sie postfix.
Wie man sieht stecht doch einiges hinter einer solchen kleinen Anweisung. Deswegen sollte man hier (wenn man will, dass der erste Fall eintritt) immer Leerzeichen setzen und dem Kompiler so genau sagen, welche operation durchgeführt werden soll!
Benutzt beim Übergeben von Werten diese Schreibweise möglichst nicht, da es zu unerwarteten Werten kommen kann. Um hier sicher zu gehen und nichts zu reskieren kann man auch die etwas längere Schreibform benutzen:
starteFunktion(variable++); //stattdessen kann man auch das nutzen:
starteFunktion(variable + 1);
Die zweite Variante übergibt ebenfalls den Wert von variable um 1 erhöht, ändert aber nicht deren Wert!
Wer mehr zu diesem Thema wissen möchte kann hier gucken: Galileo Java ist auch eine Insel




