<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Sebastian Felling</title>
	<atom:link href="http://www.felling-software.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.felling-software.com</link>
	<description>Webentwicklung, Softwareentwicklung, Web Design</description>
	<lastBuildDate>Sun, 31 Mar 2013 19:12:34 +0000</lastBuildDate>
	<language>de-DE</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
		<item>
		<title>Globetrotting in WPF: Lokalisierung leicht gemacht mit Hilfe eines zentralen Bindungshelfers – TEIL II</title>
		<link>http://www.felling-software.com/2012/12/globetrotting-in-wpf-lokalisierung-leicht-gemacht-mit-hilfe-eines-zentralen-bindungshelfers-teil-2/</link>
		<comments>http://www.felling-software.com/2012/12/globetrotting-in-wpf-lokalisierung-leicht-gemacht-mit-hilfe-eines-zentralen-bindungshelfers-teil-2/#comments</comments>
		<pubDate>Thu, 20 Dec 2012 21:46:28 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Lokalisierung]]></category>
		<category><![CDATA[WPF]]></category>
		<category><![CDATA[Globalisierung]]></category>
		<category><![CDATA[INotifyPropertyChanged]]></category>
		<category><![CDATA[Observer Pattern]]></category>
		<category><![CDATA[Publish-Subscribe Pattern]]></category>
		<category><![CDATA[Übersetzung]]></category>

		<guid isPermaLink="false">http://www.felling-software.com/?p=422</guid>
		<description><![CDATA[Im ersten Teil dieses Artikels habe ich die Anforderungen sowie erste Vorüberlegungen zu einer möglichen Implementierung eines Bindungshelfers zur ad-hoc Lokalisierung einer WPF-Anwendung vorgestellt. Im zweiten Teil möchte ich die Vorarbeit mit Hilfe einer echten Implementierung konkretisieren. Wir wollen uns möglichst viel Arbeit durch die hervorragende WPF-Datenbindung abnehmen lassen. Dazu verwenden wir das MVVM-Pattern und [...]]]></description>
				<content:encoded><![CDATA[<p><strong>Im <a title="Globetrotting in WPF: Lokalisierung leicht gemacht mit Hilfe eines zentralen Bindungshelfers – TEIL I" href="http://www.felling-software.com/2012/12/globetrotting-in-wpf-lokalisierung-leicht-gemacht-mit-hilfe-eines-zentralen-bindungshelfers-teil-1/">ersten Teil dieses Artikels</a> habe ich die Anforderungen sowie erste Vorüberlegungen zu einer möglichen Implementierung eines Bindungshelfers zur ad-hoc Lokalisierung einer WPF-Anwendung vorgestellt. Im zweiten Teil möchte ich die Vorarbeit mit Hilfe einer echten Implementierung konkretisieren.</strong></p>
<p>Wir wollen uns möglichst viel Arbeit durch die hervorragende WPF-Datenbindung abnehmen lassen. Dazu verwenden wir das <a title="MVVM Pattern" href="http://en.wikipedia.org/wiki/Model_View_ViewModel" target="_blank">MVVM-Pattern</a> und beginnen mit dem ViewModel, an das wir die UI binden können. Da wir später möglichst wenig Code zur Bindung der UI an unseren Bindungshelfer schreiben möchten, liegt es nahe, diesen in ein Basis ViewModel so zu integrieren, dass wir leichten Zugriff darauf erhalten.</p>
<h2>Die ViewModel-Basisklasse</h2>
<p>Wir definieren also zunächst unser Grundgerüst für die Basisklasse aller späteren ViewModels: ViewModelBase.</p>
<pre class="brush: csharp">public abstract class ViewModelBase : ObservableObject {

    // CTORS
    protected ViewModelBase() {}

    // PROPERTIES
    private static Translator _translator;
    public static Translator Translator
    {
        get { return _translator; }
        set {
            if (_translator == null)
                _translator = value;
            else
                throw new InvalidOperationException("Translator already initialized;");
        }
    }
    public Translator T9
    {
        get { return Translator; }
    }

}</pre>
<p>Mehrere Stellen bedürfen einer Erläuterung:</p>
<p>Da es sich um eine Basisklasse handelt, von der konkrete ViewModels abgeleitet werden sollen, ist die ViewModelBase als <em>abstract </em>definiert und kann über einen geschützten Konstruktor instantiiert werden. Die ViewModelBase stellt den Bindungshelfer als statische Eigenschaft <em>Translator</em> bereit (diese Klasse implementieren wir später). Statisch ist diese Eigenschaft, da anwendungs-weit nur eine Instanz benötigt wird und möglichst zentral darauf zugegriffen werden soll. Der Setter dieser Eigenschaft erlaubt die einmalige Instanziierung der Translator-Klasse gemäß dem <a title="Singleton Pattern" href="http://en.wikipedia.org/wiki/Singleton_pattern" target="_blank">Singleton-Pattern</a>.</p>
<p>Um die Bindung an das konkrete ViewModel zu erleichtern, kommt außerdem ein pseudo-instanzspezifischer Alias <em>T9</em> zum Einsatz, der auf die klassen-spezifische Eigenschaft <em>Translator</em> verweist. Über diesen steuern wir die Bindung der Übersetzungen und Artefakte an unsere Steuerelemente.</p>
<p>Weiterhin erbt die ViewModelBase von <em>ObservableObject</em>, welches den Kontrakt von <a title="INotifyPropertyChanged" href="http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx" target="_blank">INotifyPropertyChanged</a> mit Hilfe einer zentralen Funktion SetPropertyValue() kapselt. Diese erleichtert die Zuweisung von Werten an die VM, welche bei etwaigen Änderungen gleichzeitig die UI via <a title="Publish-Subscribe-Pattern" href="http://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern" target="_blank">Publish-Subscribe-Pattern</a> benachrichtigt.</p>
<pre class="brush: csharp">public abstract class ObservableObject : INotifyPropertyChanged
{
	// CTORS
	protected ObservableObject() {}

	// EVENTS
	public event PropertyChangedEventHandler PropertyChanged;

	// PRIVATE FIELDS
	protected virtual void OnPropertyChanged(string propertyName) {
		// wird Event überwacht?
		var handler = PropertyChanged;
		if (handler != null)
			handler(this, new PropertyChangedEventArgs(propertyName));
	}
	internal protected void SetPropertyValue(string propertyName, ref T propertyReference, T value) {
		// Wert verändert?
		if (Equals(propertyReference, value))
		return;

		// setzen und benachrichtigen
		propertyReference = value;
		OnPropertyChanged(propertyName);
	}
}</pre>
<p>Das ViewModel-Grundgerüst ist damit fertig und wir kommen zum zentralen Teil: Dem Bindungshelfer, genannt: Translator.</p>
<h2>Die Translator-Klasse: Rüstzeug</h2>
<p>Unser Bindungshelfer gewinnt gewiss keinen Preis in der Kategorie &#8220;innovative Produktnamen&#8221;. Das heißt jedoch nicht, dass es sich um eine triviale Klasse handelt. Im Gegenteil: Wir beginnen mit den zentralen Merkmalen und Anforderungen, die wir sodann in Code umsetzen.</p>
<p>Unsere Translator-Klasse ist der zentrale ad-hoc Übersetzer und hat als solcher folgende Aufgaben zu erfüllen:</p>
<ol>
<li><span style="line-height: 13px;">Erlaube die Angabe einer (aktuellen) Zielkultur, welche vorgibt, in welche Sprache und kulturellen Parameter die UI übersetzt werden soll.</span></li>
<li>Erlaube das Anlegen und Registrieren von mehreren verfügbaren Zielkulturen, zwischen denen gewechselt werden kann.</li>
<li>Erlaube das Anlegen und Registrieren von kulturspezifischen Artefakten (Text, Grafik, URIs) in Form von Schlüssel-Wert-Paaren.</li>
<li>Erlaube das direkte Umschalten zwischen den verfügbaren Zielkulturen (auch via Datenbindung); so dass die UI in Echtzeit (d.h. ohne Neustart der Anwendung) übersetzt wird.</li>
<li>Erlaube die Verwendung eines Debug-Modus, welcher fehlerhafte Bindungen noch zur Entwurfszeit sichtbar macht.</li>
<li>Erlaube es dem Programm, auf die nächstmögliche Kultur und Sprache zurückzuspringen, falls eine gewünschte Zielkultur nicht existiert (<em>Defaulting</em>).</li>
<li>Erlaube das Einlesen von Artefakten über externe (XML-) Dateien.</li>
<li>Erlaube möglichst einfaches Binden der Steuerlemente bereits zur Entwurfszeit an die Artefakte.</li>
</ol>
<p>Ich werde die Translator-Klasse im kommenden dritten Teil dieses Artikels mit Hilfe dieser Vorgaben mit Leben füllen.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.felling-software.com/2012/12/globetrotting-in-wpf-lokalisierung-leicht-gemacht-mit-hilfe-eines-zentralen-bindungshelfers-teil-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Globetrotting in WPF: Lokalisierung leicht gemacht mit Hilfe eines zentralen Bindungshelfers &#8211; TEIL I</title>
		<link>http://www.felling-software.com/2012/12/globetrotting-in-wpf-lokalisierung-leicht-gemacht-mit-hilfe-eines-zentralen-bindungshelfers-teil-1/</link>
		<comments>http://www.felling-software.com/2012/12/globetrotting-in-wpf-lokalisierung-leicht-gemacht-mit-hilfe-eines-zentralen-bindungshelfers-teil-1/#comments</comments>
		<pubDate>Sun, 16 Dec 2012 20:03:40 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Lokalisierung]]></category>
		<category><![CDATA[WPF]]></category>
		<category><![CDATA[Globalisierung]]></category>
		<category><![CDATA[INotifyPropertyChanged]]></category>
		<category><![CDATA[Observer Pattern]]></category>
		<category><![CDATA[Publish-Subscribe Pattern]]></category>
		<category><![CDATA[Übersetzung]]></category>

		<guid isPermaLink="false">http://www.felling-software.com/?p=382</guid>
		<description><![CDATA[In diesem Artikel möchte ich einen Bindungshelfer vorstellen, der es WPF-Anwendungen erlaubt, ihre Benutzerschnittstelle mit Hilfe von trivialer Datenbindung ad hoc und effizient zu lokalisieren. Viele Großprojekte für Wirtschaft und Industrie werden von Beginn an mit dem Anspruch entwickelt, sie eines Tages exportieren zu können. Für die Entwicklung stellen sich hierdurch nicht unerhebliche Herausforderungen, da [...]]]></description>
				<content:encoded><![CDATA[<p><strong>In diesem Artikel möchte ich einen Bindungshelfer vorstellen, der es WPF-Anwendungen erlaubt, ihre Benutzerschnittstelle mit Hilfe von trivialer Datenbindung ad hoc und effizient zu lokalisieren.</strong></p>
<p>Viele Großprojekte für Wirtschaft und Industrie werden von Beginn an mit dem Anspruch entwickelt, sie eines Tages exportieren zu können. Für die Entwicklung stellen sich hierdurch nicht unerhebliche Herausforderungen, da die Prozesse der <em>Globalisierung</em> und <em>Lokalisierung</em>, oft in enger Zusammenarbeit mit Designern und Fachübersetzern, geplant und koordiniert werden müssen.</p>
<p>Dabei sind die Anforderungen desto komplexer, je Kultur-unabhängiger eine Anwendung geplant werden soll. Bevor wir uns ans Werk machen, gilt es die Grundbegriffe näher zu bestimmen:</p>
<ul>
<li>Unter <strong>Globalisierung</strong> versteht man allgemein, eine Anwendung so <del>zu entwickeln</del> vorzubereiten, dass sie möglichst über keinerlei Sprach- und Kulturabhängigkeiten verfügt. Die Globalisierung einer Anwendung befähigt diese, in andere Sprachen und Kulturen übersetzt zu werden. Sie ist, so gesehen, der notwendige Schritt hin zum Übersetzen einer Anwendung. Startpunkt für eine Globalisierung ist die <em>Ausgangskultur.</em> Ihr Ziel ist ein kulturagnostisches Anwendungsgerüst.</li>
<li>Die <strong>Lokalisierung</strong> knüpft nahtlos an die Globalisierung an und meint das Übersetzen einer (globalisierten, kulturagnostischen) Anwendung in eine spezifische Sprache und Kultur (<em>Zielkultur</em>).</li>
</ul>
<div id="attachment_395" class="wp-caption alignleft" style="width: 224px"><a href="http://www.felling-software.com/2012/12/globetrotting-in-wpf-lokalisierung-leicht-gemacht-mit-hilfe-eines-zentralen-bindungshelfers-teil-i/globalisierung_lokalisierung/" rel="attachment wp-att-395"><img class=" wp-image-395   " alt="Globalisierung und Lokalisierung" src="http://www.felling-software.com/wp/wp-content/uploads/2012/12/globalisierung_lokalisierung-e1355686399900.png" width="214" height="246" /></a><p class="wp-caption-text">Globalisierung und Lokalisierung</p></div>
<p>In einem gewissen Sinn stehen sich Globalisierung und Lokalisierung gegenüber und sind doch integrative Bestandteile eines Ganzen. Beide Prozesse sind komplementär, d.h. sie erfolgen stets gemeinsam und sind aneinander gebunden. Dies lässt sich leicht erkennen, da es einerseits keine kulturagnostische (d.h. globalisierte, aber nicht lokalisierte) Anwendung geben kann, andererseits eine lokalisierte Anwendung immer die Überführung dieser aus einer Ausgangskultur bedingt.</p>
<p>Globalisierung und Lokalisierung schließen Tätigkeiten wie das Entwickeln kultur-unabhängiger Datentypen und kultur-spezifischer Datenhaltung wie auch das Übersetzen von Artefakten (Text, Grafik, Multimedia) ein. Zwar handelt sich es nach wie vor um kostenintensive Arbeiten, jedoch erleichtert das .NET Framework diese enorm &#8212; insbesondere WPF mit seiner hervorragenden Fähigkeit zur Datenbindung (Dependency Properties).</p>
<p>Ich möchte im Folgenden eine Möglichkeit aufzeigen, einen effizienten &#8220;Übersetzer&#8221; in Form eines Bindungshelfers zu schreiben, der die Eigenschaften der WPF-Datenbindungsmittel geschickt auszunutzen weiß. Es handelt sich hierbei um einen frühen Prototypen, der gewiss nur den Anfang eines solchen Unternehmens markiert und in keiner Weise den Anspruch der Vollständigkeit erhebt.</p>
<h2>Anforderungen an den Bindungshelfer</h2>
<p>Stellen wir uns vor, eine mittelgroße deutsche Anwendung soll möglichst effizient für die Globalisierung und Lokalisierung vorbereitet werden:</p>
<ol>
<li>Der Einfachheit halber wollen wir uns auf europäische Zielkulturen beschränken (z.B. germanische und romanische Sprachen).</li>
<li>Wir möchten die Artefakte (Texte, Grafiken und URIs) innerhalb von Visual Studio an die Ziel-Steuerelemente binden können, und das möglichst ohne umständlichen Schreibaufwand. Auch sollen die Entwickler bei Ihrer Arbeit nicht gestört werden, so dass sich die Artefakt-Anbindung nahtlos in den Code integrieren lassen muss.</li>
<li>Dabei sollen die Artefakte unabhängig durch Dritte (Übersetzer) bearbeitet und in die Anwendung injiziert werden können, wobei bereits beim Debuggen des Quelltexts Bindungsfehler erkannt werden sollen.</li>
<li>Zu guter Letzt soll es dem Anwender möglich sein, die Benutzeroberfläche per einfachem Klick und ohne Neustart der Anwendung zu &#8220;übersetzen&#8221;.</li>
</ol>
<h2>Vorüberlegungen zu einer möglichen Implementierung</h2>
<p>Da wir uns auf i.w.S. europäische Kulturen, insbesondere romanische und germanische Sprachen, beschränken wollen (Anforderung 1), können wir das zwar spannende aber anspruchsvolle Problem der Linksläufigkeit von Sprachen (z.B. im Arabischen) außer Acht lassen. (Kurz notiert: Mit dieser Aussage stecken wir bereits in unserer eingeschränkten, westlichen Sichtweise fest [für eben jene Araber sind linksläufige Sprachen mitnichten ein Problem, wohl aber Textverarbeitungsprogramme westlicher Entwickler]. Wir geben also den Anspruch an eine echte Globalisierung zum Wohle der didaktischen Simplifizierung auf.)</p>
<p>Das Bindungsverhalten wird durch WPF vorgegeben und eignet sich mit seinen <a title="Observer pattern" href="http://en.wikipedia.org/wiki/Observer_pattern" target="_blank">Observer</a> und <a title="Publish–subscribe pattern" href="http://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern" target="_blank">Publish–Subscribe</a> Patterns  hervorragend für die Implementierung eines Übersetzungshelfers, der ad hoc zwischen den Zielsprachen wechseln kann (Anforderungen 2 und 4). Die zentrale Steuerung erfolgt hier über die <a title="INotifyPropertyChanged-Schnittstelle" href="http://msdn.microsoft.com/de-de/library/system.componentmodel.inotifypropertychanged.aspx" target="_blank"><em>INotifyPropertyChanged</em></a> Implementierung des ViewModels, das im Falle eines Umschaltens zwischen den Sprachen die Neubindung der Artefakte an die UI veranlässt.</p>
<p>Wir binden unsere Zielsteuerelemente (Dependency Objects) wie gewohnt per Data Binding an die Artefakte an, um den Entwicklern eine nahtlose Integration der Übersetzung(en) in ihren Code zu ermöglichen. Um den zu schreibenden Code gering zu halten, erlauben wir den Zugriff auf die Artefakte über indizierte Eigenschaften (<a title="Indexed Properties" href="http://msdn.microsoft.com/en-us/library/aa288464(v=vs.71).aspx" target="_blank">Indexed Properties</a>) einer zentralen Übersetzungsinstanz (<a title="Singleton pattern" href="http://en.wikipedia.org/wiki/Singleton_pattern" target="_blank">Singleton</a> Pattern), die über das ViewModel direkt zur Verfügung gestellt wird.</p>
<p>Die gewünschten Artefakttypen (Text, Grafik und URI) lassen sich leicht auf die CLR-Typen <em>string, image source</em> und <em>uri</em> mappen. Durch Ausgliederung der Übersetzungen in externe XML- und Grafik-Ressourcen erreichen wir ferner eine strikte Trennung zwischen der Zurverfügungstellung und dem Konsumieren der Artefakte (Anforderung 3). Diese können z.B. über eine externe XML-Datei zu Programmstart in die Anwendung injiziert werden und eigenen sich ebenfalls als Ziel für die redaktionelle Bearbeitung durch Drittanwendungen (z.B. Excel).</p>
<p>Mit diesen Vorüberlegungen im Gepäck sind wir für die weiteren Arbeitsschritte bestens vorbereitet und können uns nun an die eigentliche Code-Implementierung machen.</p>
<p><strong><a title="Globetrotting in WPF: Lokalisierung leicht gemacht mit Hilfe eines zentralen Bindungshelfers – TEIL II" href="http://www.felling-software.com/2012/12/globetrotting-in-wpf-lokalisierung-leicht-gemacht-mit-hilfe-eines-zentralen-bindungshelfers-teil-2/">In einem zweiten Teil</a> werde ich die Implementierung in Kürze konkretisieren&#8230;</strong></p>
]]></content:encoded>
			<wfw:commentRss>http://www.felling-software.com/2012/12/globetrotting-in-wpf-lokalisierung-leicht-gemacht-mit-hilfe-eines-zentralen-bindungshelfers-teil-1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ObservableCollection 2.0 — Oder: Wie man Termine beisammen hält</title>
		<link>http://www.felling-software.com/2012/10/observablecollection-2-0-oder-wie-man-termine-beisammen-halt/</link>
		<comments>http://www.felling-software.com/2012/10/observablecollection-2-0-oder-wie-man-termine-beisammen-halt/#comments</comments>
		<pubDate>Tue, 30 Oct 2012 19:18:05 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[Entity Framework]]></category>
		<category><![CDATA[WPF]]></category>
		<category><![CDATA[INotifyCollectionChanged]]></category>
		<category><![CDATA[INotifyPropertyChanged]]></category>
		<category><![CDATA[ObservableCollection]]></category>

		<guid isPermaLink="false">http://www.felling-software.com/?p=326</guid>
		<description><![CDATA[Aktuell arbeite ich in einem Team aus drei Entwicklern an einer Termin- und Mitarbeiterverwaltung für einen industriellen Großkunden. Eine der vielen Anforderungen an unsere Lösung lautet (Auszug aus dem Scrum-Board): Als Innendienstler möchte ich Aufträgen Termine zuweisen können, um den Personaleinsatz (Techniker) vor Ort optimieren zu können. Zu jedem Auftrag sollen die Termine in Echtzeit [...]]]></description>
				<content:encoded><![CDATA[<p>Aktuell arbeite ich in einem Team aus drei Entwicklern an einer Termin- und Mitarbeiterverwaltung für einen industriellen Großkunden. Eine der vielen Anforderungen an unsere Lösung lautet (Auszug aus dem Scrum-Board):</p>
<p><strong>Als Innendienstler möchte ich Aufträgen Termine zuweisen können, um den Personaleinsatz (Techniker) vor Ort optimieren zu können. Zu jedem Auftrag sollen die Termine in Echtzeit ersichtlich sein. Jeder Auftrag soll den frühesten Termin explizit anzeigen.</strong></p>
<p>Zum Hintergrund: Die mittels WPF in .NET 4 umgesetzte Anwendung ist mehrbenutzerfähig und verwendet einen SQL Server 2012 zur Datenhaltung. Zum Einsatz kommt außerdem das aktuelle <a title="Entity Framework 5" href="http://msdn.microsoft.com/de-de/data/ef">Entity Framework 5.0</a>.</p>
<h3>Gesucht: Datencontainer für Termine</h3>
<p>Um die oben genannte Anforderung zu erfüllen, benötigten wir einen Container, der&#8230;</p>
<ul>
<li>generische Items aufnehmen kann (wir arbeiten mit einer Klasse <em>Termin</em>),</li>
<li>sich nahtlos an die UI binden lässt, sowie</li>
<li>Änderungen im Items-Bestand automatisch mitteilt (<em>INotifyCollectionChanged, INotifyPropertyChanged</em>).</li>
</ul>
<p>Die Klasse <em>Termin</em> definiert die Eigenschaften <strong>Start</strong> und <strong>Ende</strong> (beide <em>DateTime</em>) und sieht im Kern wie folgt aus (Auszug):</p>
<pre class="brush: csharp">public class Termin : ObservableObject
{
    // PRIVATE BACKING VARS
    private DateTime _start;
    private DateTime _ende;

    // CTORS
    public Termin(DateTime start, TimeSpan dauer)
    {
        // validiere
        if(start == null)
            throw new ArgumentNullException("start");

        if(dauer == null)
            throw new ArgumentNullException("dauer");

        // zuweisen
        Start = start;
        Ende = start.Add(dauer);
    }

    // PROPERTIES
    public DateTime Start
    {
        get { return _start; }
        set { SetPropertyValue("Start", ref _start, value); }
    }
    public DateTime Ende
    {
        get { return _ende; }
        set { SetPropertyValue("Ende", ref _ende, value); }
    }
}</pre>
<p>Der gesuchte Container soll es der Klasse <em>Auftrag</em> ermöglichen, seine <strong>Termine</strong> über die gleichnamige Eigenschaft Clients zur Verfügung zu stellen, so dass dem Auftrag beliebig Termine hinzugefügt und entfernt werden können:</p>
<pre class="brush: csharp">public class Auftrag : ObservableObject
{
    // PRIVATE BACKING VARS
    private ObservableCollection&lt;Termin&gt; _termine;
    private Termin _fruehesterTermin;

    // CTORS
    public Auftrag()
    {
        // instantiiere
        Termine = new ObservableCollection&lt;Termin&gt;();
    }

    // PROPERTIES
    public Termin FruehesterTermin
    {
        get { return _fruehesterTermin; }
        private set { SetPropertyValue("FruehesterTermin", ref _fruehesterTermin, value); }
    }
    public ObservableCollection&lt;Termin&gt; Termine
    {
        get { return _termine; }
        private set { SetPropertyValue("Termine", ref _termine, value); }
    }
}</pre>
<h3>Berechnung des Wertes <em>Auftrag</em>.FruehesterTermin</h3>
<p>Änderungen im Termin-Bestand müssen deshalb abgefangen werden, damit der Wert <strong>FruehesterTermin</strong> eines Auftrags neu berechnet werden kann. Diese Neuberechnung wird erforderlich, wann immer</p>
<ul>
<li>sich der früheste Termin durch das Hinzufügen oder Entfernen von Terminen aus der Collection ändert, oder auch</li>
<li>das Ändern von Eigenschaften bestehender Termine (insbes. der <strong>Start</strong>-Eigenschaft) eine Neuberechnung von <em>Auftrag</em>.<strong>FruehesterTermin</strong> erforderlich macht.</li>
</ul>
<p>Unter den potentiellen Kandidaten stand natürlich die generische <a title="ObservableCollection T" href="http://msdn.microsoft.com/de-de/library/vstudio/ms668604.aspx">ObservableCollection&lt;T&gt;</a> an erster Stelle, die uns WPF-Entwicklern sehr gute Dienste erweist. Die Sache hat jedoch einen Haken: Zwar meldet die <em>ObservableCollection&lt;T&gt;</em> Änderungen im Items-Bestand über das Ereignis <a href="http://msdn.microsoft.com/de-de/library/system.collections.specialized.inotifycollectionchanged.collectionchanged.aspx">CollectionChanged</a> (INotifyCollectionChanged), so z.B. beim Hinzufügen und Entfernen von Terminen. Jedoch werden Änderungen innerhalb von Terminen (z.B. das Ändern eines <strong>Start</strong>-Datums) nicht über die Collection selbst an Dritte weitergegeben. Dies ist jedoch erforderlich, um sicherzustellen, dass ein Auftrag seinen Wert <strong>FruehesterTermin</strong> neu berechnen kann, wenn sich die Start-Werte seiner Termine ändern.</p>
<h3>ObservableCollection&lt;T&gt; erweitert: DeeplyObservableCollection&lt;T&gt;</h3>
<p>Wir beauftragen also die ObservableCollection mit der Beobachtung seiner Items. Da dies nicht von Haus aus implementiert ist, erweitern wir die Klasse durch den abgeleiteten Typen <em>DeeplyObservableCollection&lt;T&gt;</em>. Dieser beobachtet Änderungen in seinem Items-Bestand bis hinunter zu den Properties der Items. Dazu ist es erforderlich, dass nur Items aufgenommen werden können, die <em>INotifyPropertyChanged</em> implementieren:</p>
<pre class="brush: csharp">public class DeeplyObservableCollection : ObservableCollection where T : INotifyPropertyChanged
{
    // CTORS
    public DeeplyObservableCollection() : base() {
        // auf Bestandsänderungen reagieren
        CollectionChanged += DeeplyObservableCollection_CollectionChanged;
    }
}</pre>
<p>Änderungen am Items-Bestand werden durch das Ereignis <strong>CollectionChanged</strong> abgefangen. Neue Items werden ebenfalls über PropertyChanged auf Änderungen beobachtet:</p>
<pre class="brush: csharp">private void DeeplyObservableCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
    // reagiere auf Änderungen innerhalb von items
    if(e.NewItems != null) {
        foreach(var item in e.NewItems)
            (item as INotifyPropertyChanged).PropertyChanged += DeeplyObservableCollection_Item_PropertyChanged;
    }

    // löse Ereignis-Handler von alten Elementen
    if(e.OldItems != null) {
        foreach (var item in e.OldItems)
            (item as INotifyPropertyChanged).PropertyChanged -= DeeplyObservableCollection_Item_PropertyChanged;
    }
}</pre>
<p>Schließlich sollen Änderungen innerhalb von Items durch das Ereignis <strong>CollectionChanged</strong> der zugrundeliegenden ObservableCollection an Clients weitergegeben werden. Dazu zweckentfremden wir die <em>NotifyCollectionChangedAction</em>:</p>
<pre class="brush: csharp">private void DeeplyObservableCollection_Item_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
    // Event feuern
    var e2 = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace);
    OnCollectionChanged(e2);
}</pre>
<h3>Das Resultat</h3>
<p>Jetzt können wir Änderungen an unseren Terminen sowohl auf Collection- als auch Item-Ebene bequem über das <strong>CollectionChanged</strong>-Ereignis unserer <em>DeeplyObservableCollection</em> abfangen, um dann den Wert <strong>FruehesterTermin</strong> neu berechnen lassen. Zuerst aber müssen wir die ObservableCollection-Instanzen durch unsere neue DeeplyObservableCollection austauschen:</p>
<pre class="brush: csharp">public class Auftrag : ObservableObject
{
    // PRIVATE BACKING VARS
    private DeeplyObservableCollection _termine;

    // ...

    // CTOR
    public Auftrag()
    {
        // instantiiere
        Termine = new DeeplyObservableCollection();

        // Änderungen abfangen
        Termine.CollectionChanged += Termine_CollectionChanged;
    }

    // EVENT HANDLERS
    private void Termine_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        // fruehesten Termin neu berechnen
        FruehesterTermin = Termine.OrderBy(t =&gt; t.Start).FirstOrDefault();
    }
}</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.felling-software.com/2012/10/observablecollection-2-0-oder-wie-man-termine-beisammen-halt/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Laravel PHP Framework: Ästhetik trifft Objektorientierung</title>
		<link>http://www.felling-software.com/2012/07/laravel-php-framework-aesthetik-trifft-objektorientierung/</link>
		<comments>http://www.felling-software.com/2012/07/laravel-php-framework-aesthetik-trifft-objektorientierung/#comments</comments>
		<pubDate>Tue, 24 Jul 2012 07:55:46 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Programmierung]]></category>
		<category><![CDATA[Laravel]]></category>
		<category><![CDATA[Objektorientierung]]></category>
		<category><![CDATA[Taylor Otwell]]></category>

		<guid isPermaLink="false">http://www.stylescouts.local/wp/?p=1</guid>
		<description><![CDATA[Laravel heißt das dem streng objektorientierten Paradigma unterworfenen Web Application Framework, das PHP Entwicklern das Leben leichter machen soll. Mehr noch: Es hat den Anspruch, die Entwicklung selbst zur Freude werden zu lassen. Und den erfüllt es auf ganzer Linie.]]></description>
				<content:encoded><![CDATA[<p>Wer auf der Suche nach einem flexiblen und leichtgewichtigen PHP-Framework für Webanwendungen ist, das sich streng an objektorientierte Prinzipien und das MVC-Pattern hält, sollte sich <a title="Laravel" href="http://laravel.com/" target="_blank">Laravel</a> unbedingt anschauen.</p>
<p>Das von <a href="http://laravel.com/about" target="_blank">Taylor Otwell</a> entwickelte Web Application Framework kommt frisch und frech daher. Es verzichtet auf die PHP-Altlasten, die viele andere PHP Frameworks mit sich herum schleppen. Grund dafür dürfte sein, dass Otwell langjähriger .NET Entwickler ist und erst spät in PHP geschrieben hat, als eine ausreichende objektorientierte Unterstützung gegeben war.</p>
<p>Sein Anspruch: ein intuitives, expressives Web Framework, das die modernen Features der aktuellen PHP-Version 5.3 unterstützt, einfach zugänglich und gut dokumentiert ist. Nebenbei preist er es als ein Werkzeug an, das die Entwicklung zur Freude macht. Recht hat er: Laravel macht viel Freude.</p>
<h3>Objektorientierung bis zur Perfektion</h3>
<p>Laravel glänzt durch seinen konsequenten objektorientierten Ansatz. Alles, aber auch wirklich alles wird über Klassen bereitgestellt, die sich nahezu beliebig erweitern lassen. Mehr noch: Wo Objektmethoden keinen Sinn haben, übernehmen statische Funktionen die Aufgaben, die unabhängig von einzelnen Instanzen ausgeführt werden, z.B. das Auslesen von Input über via GET:</p>
<pre class="brush: php">$your_name = Input::get('your_name', 'John Doe');</pre>
<h3>Artisan und Projektstruktur</h3>
<p><img class=" wp-image-187 alignleft" title="Laravel Projektstruktur" alt="" src="http://www.felling-software.com/wp/wp-content/uploads/2012/07/laravel_project_structure.jpg" /></p>
<p><em>Artisan</em> (zu Deutsch: <em>Handwerker</em>) heißt der Projektassistent, der für das Generieren der Basis-Implementierung zuständig ist (sog. <a href="http://en.wikipedia.org/wiki/Scaffold_(programming)" target="_blank">Scaffolding</a>). Insofern ist der Name gut gewählt, da dieser tatsächlich die wichtige Handarbeit erledigt.</p>
<p>So wird u.a. die Projektstruktur über die Kommandozeile von <em>Artisan</em> bereitgestellt. Sie entspricht dem üblichen <em>Convention over Configuration</em> Credo.</p>
<p>Die Abbildung links lässt die konsequente Sauberkeit schon erahnen, die sich durch das gesamte Framework bis hin zur Perfektion zieht. Gerade das aber macht die Freude an Laravel aus, denn die Arbeit damit gestaltet sich äußerst effizient und produktiv.</p>
<p>Auch beim Migrieren der Daten und dem Erstellen neuer Controller hilft Artisan ungemein.</p>
<h3>MVC und Routing</h3>
<p>Es folgt ein einfaches Beispiel für Laravels MVC-Unterstützung.</p>
<pre class="brush: php">    class Home_Controller extends Base_Controller {
        public function action_index() {
            return View::make('index.index');
        }
        public function action_about() {
            return View::make('home.about');
        }
    }</pre>
<p>MVC-Kennern zeigt der Code-Ausschnitt nichts Neues: Alle Controller erben von Base_Controller und stellen die nächst kleineren logischen Einheiten (Actions) bereit. Die <em>About</em> <em>Action</em> des <em>Home Controller </em>ließe sich bsplws. über die URL <strong>/home/about</strong> aufrufen.</p>
<h3>Weitere Goodies und Fazit</h3>
<p>Die vorgestellten Features sind nur die Spitze des Eisberges: Laravel hat noch mehr Leckerbissen an Bord:</p>
<ul>
<li>Routes und Closures,</li>
<li>Form-Generierung und -Validierung,</li>
<li>Query Builder (<em>Fluent</em>) sowie OR-Mapper (<em>Eloquent</em>),</li>
<li>Templates (<em>Blade</em>),</li>
<li>Authentication und Event Handling</li>
</ul>
<p>Insgesamt präsentiert sich Laravel als kompaktes, modernes und hoch effizientes Framework. Die Arbeit damit macht nicht nur Spaß, man ist auch sehr schnell mit hoher Produktivität dabei. Die <a href="http://laravel.com/" target="_blank">offizielle Homepage</a> bietet eine ausführliche <a href="http://laravel.com/docs" target="_blank">Dokumentation</a>, <a href="http://forums.laravel.com/" target="_blank">Benutzerforen</a> sowie <a href="http://bundles.laravel.com/" target="_blank">kostenlose Erweiterungen</a> (sogen. <em>Bundles</em>).</p>
<p>Ich bin sicher, wir werden in Zukunft noch viel von Otwell und seinem vielversprechenden Framework hören.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.felling-software.com/2012/07/laravel-php-framework-aesthetik-trifft-objektorientierung/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Barrierefreiheit: Wie barrierearm darf es denn sein?</title>
		<link>http://www.felling-software.com/2012/07/barrierefreiheit-trade-off-zwischen-ideal-und-budget/</link>
		<comments>http://www.felling-software.com/2012/07/barrierefreiheit-trade-off-zwischen-ideal-und-budget/#comments</comments>
		<pubDate>Thu, 12 Jul 2012 19:34:58 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Barrierefreiheit]]></category>
		<category><![CDATA[Best Practices]]></category>
		<category><![CDATA[Accessibility]]></category>
		<category><![CDATA[Barrierearmut]]></category>
		<category><![CDATA[BITV]]></category>

		<guid isPermaLink="false">http://www.stylescouts.local/?p=29</guid>
		<description><![CDATA[Barrierefreiheit ist eine nicht bloß erstrebenswerte, sondern notwendige Voraussetzung guten Web Designs. Doch auch über zehn Jahre nach Ergänzung des Behindertengleichstellungsgesetzes durch die BITV ist noch viel im Argen. Der Grund ist simpel: Barrierefreiheit ist teuer.]]></description>
				<content:encoded><![CDATA[<p>Barrierefreiheit ist gut und richtig, das ist die landläufige Meinung unter Webentwicklern und Auftraggebern. Wir lassen einmal den Unterschied zwischen dem Prinzip Barrierefreiheit und der Realität Barrierearmut außer Betracht. Ebenso interessieren mich hier nicht die Aspekte der <em>Accessibility</em> im Sinne einer geräte-übergreifenden Zugänglichkeit von Inhalten. Es geht mir hier ausschließlich um das zentrale Anliegen von Barrierefreiheit: Das Aufbereiten von Webinhalten für Menschen mit Behinderungen.</p>
<p>Staatliche Stellen sind verpflichtet, ihre Webauftritte möglichst barrierearm zu gestalten (bzw. gestalten zu lassen) und budgetieren entsprechend. Private Auftraggeber und solche aus der freien Wirtschaft hingegen halten einen barrierearmen Webauftritt zwar für erstrebenswert. Von ihrem hehren Anspruch bleibt jedoch nicht viel, sobald es um die Bereitstellung finanzieller Mittel geht.</p>
<h3>Die Kosten von Barrierefreiheit</h3>
<p>Zwar ist der Aufwand, barrierearme Seiten und Webanwendungen zu schreiben, dank moderner Webtechniken (XHTML, HTML5, CSS) enorm gesunken. Gleichzeitig jedoch wird die positive Entwicklung durch anspruchsvollere inhaltliche Gestaltung und gestiegene Ansprüche der Besucher konterkariert.</p>
<p>Machen wir uns nichts vor: Barrierearmut im Web ist teuer. Sie verursacht Fixkosten und laufende Kosten, die in jedem Projekt eingeplant werden müssen. Das fängt beim Entwickler an, denn der möchte für den Zusatzaufwand bezahlt werden (Fixkosten: Entwicklung). Allein mit validem XHTML/HTML5 konformem Code und ein Paar alt-Attributen für Image-Tags ist es nämlich lange nicht getan.</p>
<p>Schließlich hat der Kunde von dem Aufwand nichts, wenn er den durch ihn generierten Inhalt nicht streng nach barrierearmen Prinzipien gestaltet (laufende Kosten: Content-Pflege): Bilder müssen mit Alternativtexten versehen werden und Videos gänzlich alternativen Content bereitstellen. Die Nachrichten vieler audiovisueller Gimmicks (man denke gerade an die zahlreichen Neuerungen im Bereich CSS3) werden dem Besucher mit Behinderung entweder gänzlich verwehrt, oder aber nur sehr eingeschränkt zugänglich gemacht.</p>
<p>Die multimediale Collage aus Texten, Grafiken, Videos und Audiodaten muss als Ganzes strengen Tests und Simulationen unterzogen werden — und das immer und immer wieder. Nur so kann sichergestellt werden, dass ihre Barrierefreiheit kein bloß theoretischer Anspruch ist. Es ist klar zu sehen, welche Kostenfaktoren hier eine Rolle spielen. Letzten Endes ist es im Bauwesen und in der Architektur, wo der Begriff Barrierefreiheit schon viele Jahrzehnte eine zentrale Rolle spielt, nicht anders.</p>
<h3>Das Problem: Barrieren und ihre Opfer sieht der Betreiber einer Site nicht</h3>
<p>Zynisch gesagt müsste es eigentlich lauten: Der Aufwand für Barrierefreiheit rechnet sich nicht (sprich: Rendite gleich null). Nun möchte ich aber meinen Kunden solch zynische Ansichten nicht unterstellen. Ich glaube daher, dass ein Hauptproblem darin besteht, dass Barrieren schlichtweg nicht erkannt werden.</p>
<p>Damit meine ich zum einen, dass strukturelle Hindernisse (z.B. die Zugänglichkeit von visuellen Medien für Sehbehinderte) nicht immer offensichtlich sind, und sich somit der Gedanke um die Notwendigkeit ihrer Vermeidung nicht gerade aufdrängt. Umso schlimmer ist es, wenn der Betreiber selbst weder Mitarbeiter mit solchen Beeinträchtigungen eingestellt hat noch selbst solchen Beeinträchtigungen unterworfen ist.</p>
<p>Zum anderen, und das halte ich für weitaus wichtiger, ist nicht ersichtlich, wie Besucher an solchen Barrieren gehindert werden oder ganz verzweifeln. Jede Treppe stellt für einen Rollstuhlfahrer ein nahezu unüberbrückbares Hindernis dar. Das ist für jeden sofort ersichtlich. Nicht sehen hingegen können wir, wie der Sehbehinderte den Inhalt kontrastarmer visueller Medien nicht wahrnehmen kann, oder an der Nutzung einer Site mangels alternativer Auszeichnungen gänzlich verzagt.</p>
<p>Wo die Opfer dieser unzulänglichen Aufbereitung von Medien nicht gesehen werden, kann folglich auch keine Abhilfe geschaffen, geschweige denn ein Bewusstsein um deren Nöte etabliert werden.</p>
<h3>Die Lösung?</h3>
<p>Zunächst einmal sei angemerkt, dass natürlich nicht jedes Projekt das Budget für eine nahezu barrierefreie Aufbereitung mitbringt (oder mitbringen müsste). Hier verhält es sich wie im realen Leben, wo auch nicht jeder Betrieb einen barrierefreien Zugang zu allen Räumlichkeiten anbieten kann. Letzten Endes sind also die Kostengründe immer entscheidend.</p>
<p>Die Betreiber aber, die auf einen barrierefreien Zugang nicht verzichten können, wollen oder müssten, täten gut daran, sich das Web einmal aus der Perspektive jener anzusehen, die es tatsächlich mit Beeinträchtigungen erleben. Dazu gibt es web- und anwendungsbasierte Simulatoren sowie Hilfsmittel für zahlreiche Beeinträchtigungen.</p>
<p>Wer das Web einmal aus der Perspektive von z.B. Blinden (Screenreader <a title="Screenreader WebAnywhere der University of Washington" href="http://webanywhere.cs.washington.edu/" target="_blank">hier</a> und <a title="NonVisual Desktop Access (NVDA) is a free and open source screen reader for the Microsoft Windows operating system" href="http://www.nvda-project.org/" target="_blank">hier</a>)  erlebt hat, geht die Aufbereitung der eigenen Inhalte kritischer an und neigt eher dazu, ein Verständnis für die Notwendigkeit und Richtigkeit von barrierearmer Webentwicklung aufzubringen.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.felling-software.com/2012/07/barrierefreiheit-trade-off-zwischen-ideal-und-budget/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
