<?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>AWZhome</title>
	<atom:link href="http://www.awzhome.de/feed" rel="self" type="application/rss+xml" />
	<link>http://www.awzhome.de</link>
	<description></description>
	<lastBuildDate>Thu, 16 Feb 2012 23:55:47 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Unerwünschte Facebook-Aktivitäten eindämmen mit NoScript</title>
		<link>http://www.awzhome.de/pages/271</link>
		<comments>http://www.awzhome.de/pages/271#comments</comments>
		<pubDate>Thu, 16 Feb 2012 23:53:43 +0000</pubDate>
		<dc:creator>Rpinski</dc:creator>
				<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://www.awzhome.de/?p=271</guid>
		<description><![CDATA[Dass Facebook so viele Daten wie möglich von seinen Nutzern einsammelt und verwertet, dürfte inzwischen vielen bekannt sein. Das Firefox Add-On "NoScript" kann helfen, diese Aktivitäten zu beschränken, ohne auf Facebook selbst verzichten zu müssen.]]></description>
			<content:encoded><![CDATA[<p>Dass Facebook so viele Daten wie möglich von seinen Nutzern einsammelt und verwertet, dürfte inzwischen vielen bekannt sein. So langsam dringt den Leuten auch ins Bewusstsein, dass Facebook auch fremde Seiten im Internet als Informationsquelle nutzt.</p>
<h2>So geht Facebook vor</h2>
<p>Der klassische Weg ist der viel gescholtene &#8220;Gefällt mir&#8221; Button. Zahlreiche Seiten binden ihn ein. Besucht nun ein Facebook-Nutzer eine solche Seite, lädt diese die Button-Grafik inkl. eines JavaScripts vom Facebook Server herunter. Ist der Besucher parallel in Facebook eingeloggt, erkennt der Server ihn wieder und kann somit protokollieren, dass Facebook-User X auf Seite Y war. Man bedenke dabei, dass es dazu absolut nicht nötig ist, aktiv auf den &#8220;Gefällt mir&#8221; Button zu klicken!</p>
<p>Prinzipiell ist es gar nicht notwendig, dass der Benutzer zum Zeitpunkt des Seitenbesuchs bei Facebook eingeloggt ist. Es genügt bereits, dass er irgendwann früher auf diesem Rechner mindestens einmal eingeloggt war und das dabei angelegte Cookie noch vorhanden ist. Das reicht zur Identifizierung des Nutzers völlig aus.</p>
<p>Seiten haben theoretisch sogar noch mehr Möglichkeiten zu evtl. ungewollten Datenlieferungen, z.B. das Mitteilen von gerade abgespielten Songs oder gar getätigte Käufe in Online-Shops. Das von Facebook dazu bereitgestellte Open Graph API wird immer weiter ausgebaut.</p>
<h2>Was kann man tun?</h2>
<p>Der radikalste, aber wohl sicherste Weg ist natürlich der Verzicht auf einen Facebook-Account. Es ist klar, dass das für viele nicht in Frage kommt. Auch ich möchte Facebook weiterhin nutzen, will aber dessen Sammelaktivitäten v.a. außerhalb dessen Seite behindern. Als Firefox-Nutzer hat man mit dem Add-On <a href="http://noscript.net/" target="_blank">NoScript</a> ein hilfreiches Werkzeug.</p>
<p>Allgemein dient NoScript dazu, den Anwender gegen Angriffe durch schädliche JavaScripts auf Webseiten zu schützen. Besonders interessant ist dabei dessen Funktion <a href="http://noscript.net/abe/" target="_blank">ABE (Application Boundaries Enforcer)</a>. Sie ermöglicht die Definition von beliebigen benutzerdefinierten Regeln, um ungewollte Webseitenaktivitäten einzuschränken. Die Konfiguration verbirgt sich in den NoScript-Einstellungen unter <em>Erweitert</em> und <em>ABE</em>.</p>
<p style="text-align: center;"><img class="aligncenter  wp-image-272" title="noscript_abe" src="http://www.awzhome.de/wp-content/uploads/noscript_abe.png" alt="" width="664" height="215" /></p>
<p>Im Textfeld können mit Hilfe einer definierten Syntax die Regeln eingegeben werden. Eine Regel für Facebook liefert bereits die oben verlinkte Dokumentation zu ABE. Leicht abgewandelt ist sie auf meinen Rechnern folgendermaßen im Einsatz:</p>
<pre class="brush: plain; title: ; notranslate">
# Zugriffe auf Facebook-Server von Nicht-Facebook-Seiten blockieren
Site .facebook.com .fbcdn.net .facebook.net
Accept from .facebook.com .fbcdn.net .facebook.net
Deny INCLUSION
</pre>
<p>Die Regel besagt:</p>
<ul>
<li>Zugriffe auf Inhalte von Facebook Servern dürfen nur von Seiten erfolgen, die selbst auf einem Facebook Server liegen. Damit ist die Nutzung von Facebook selbst weiterhin unbeschränkt möglich.</li>
<li>Zugriffe auf jegliche Facebook Inhalte von fremden Seiten aus werden nicht gestattet bzw. ausgefiltert. Auf diese Weise können also weder die &#8220;Gefällt mir&#8221; Buttons, noch die dazugehörigen JavaScripts vom Facebook Server nachgeladen werden. Es findet keine Kommunikation dorthin statt.</li>
</ul>
<h2>Und weiter?</h2>
<p>Selbst wenn Facebook durchaus mit Vorsicht zu genießen ist, viel spannender ist der Fall mit Google. Eine ähnliche ABE-Regel für Google zu definieren, hilft zwar gegen die ebenbürtigen &#8220;+1&#8243; Buttons auf anderen Seiten, doch leider nicht gegen die Datenspuren auf Google-Seiten selbst. Denn leider nutzt man z.B. nicht nur Google Plus als Social Network, sondern auch die alltägliche Suchmaschine, Google Maps, evtl. auch Docs oder Google Mail. Auch hier findet mit großer Sicherheit im Hintergrund eine Verknüpfung der Benutzeraktivitäten zu einem großen Benutzerprofil statt.</p>
<p>Aber diesem Thema würde ich beizeiten einen eigenen Beitrag widmen.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.awzhome.de/pages/271/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Wenn Firefox und Thunderbird nicht mehr nach Updates suchen wollen</title>
		<link>http://www.awzhome.de/pages/260</link>
		<comments>http://www.awzhome.de/pages/260#comments</comments>
		<pubDate>Wed, 09 Nov 2011 23:31:15 +0000</pubDate>
		<dc:creator>Rpinski</dc:creator>
				<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://www.awzhome.de/?p=260</guid>
		<description><![CDATA[Ein kleiner Fall aus dem Alltag: Seit einigen Monaten hatte ich auf meinen zwei Rechnern (Windows Vista + Windows 7) das Problem, dass Firefox und Thunderbird grundsätzlich nicht nach Updates suchen wollten, wenn ich als eingeschränkter Benutzer angemeldet war...]]></description>
			<content:encoded><![CDATA[<p>Ein kleiner Fall aus dem Alltag: Seit einigen Monaten hatte ich auf meinen zwei Rechnern (Windows Vista + Windows 7) das Problem, dass Firefox und Thunderbird grundsätzlich nicht nach Updates suchen wollten, wenn ich als eingeschränkter Benutzer angemeldet war. Ich konnte zwar den About-Dialog öffnen und dort &#8220;Nach Updates suchen&#8221; anklicken, doch statt zu suchen starteten beide einfach neu&#8230; und alles blieb beim alten. Startete ich sie dagegen mit Administratorrechten, aktualisierten sich beide willig. Das ist natürlich extrem lästig, wenn man normalerweise nicht als Administrator arbeitet.</p>
<p>Es zog sich über alle Versionssprünge von 3.5, 4, 5&#8230; bis 8. Auch ein komplettes Überspielen mit einem manuell heruntergeladenen Setup änderte nichts. Ein Artikel der MozillaZine brachte schließlich die Idee:</p>
<p><a href="http://kb.mozillazine.org/Software_update#Software_Update_not_working_properly" target="_blank">http://kb.mozillazine.org/Software_update#Software_Update_not_working_properly</a></p>
<p>Einer der früheren Updates muss irgendeine Form von Schaden in den Update-Infos hinterlassen haben. Was half, war das Löschen folgender Verzeichnisse (gilt ab Windows Vista):</p>
<p><em>C:\Users\&lt;Benutzername&gt;\AppData\Local\Mozilla\Firefox\Mozilla Firefox</em><br />
<em>C:\Users\&lt;Benutzername&gt;\AppData\Local\Thunderbird\Mozilla Thunderbird</em></p>
<p>Danach konnten beide wieder nach Updates suchen, ohne sie extra mit Admin-Rechten starten zu müssen.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.awzhome.de/pages/260/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Neue Rubrik &#8220;Technology&#8221;</title>
		<link>http://www.awzhome.de/pages/263</link>
		<comments>http://www.awzhome.de/pages/263#comments</comments>
		<pubDate>Wed, 09 Nov 2011 23:29:43 +0000</pubDate>
		<dc:creator>Rpinski</dc:creator>
				<category><![CDATA[AWZhome]]></category>

		<guid isPermaLink="false">http://www.awzhome.de/?p=263</guid>
		<description><![CDATA[Im Seitenmenü gibt es nun einen neuen Eintrag: Technology. In diesem Unter-Blog finden sich in Zukunft vermischte Themen rund um den Computeralltag.]]></description>
			<content:encoded><![CDATA[<p>Im Seitenmenü gibt es nun einen neuen Eintrag: <a href="http://www.awzhome.de/pages/category/technology">Technology</a>. In diesem Unter-Blog finden sich in Zukunft vermischte Themen rund um den Computeralltag.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.awzhome.de/pages/263/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Logging im NQ Core</title>
		<link>http://www.awzhome.de/pages/252</link>
		<comments>http://www.awzhome.de/pages/252#comments</comments>
		<pubDate>Sat, 08 Oct 2011 14:35:05 +0000</pubDate>
		<dc:creator>Rpinski</dc:creator>
				<category><![CDATA[NQ]]></category>

		<guid isPermaLink="false">http://www.awzhome.de/?p=252</guid>
		<description><![CDATA[Der NQ Core bietet einige einfache Funktionen zum Loggen von Informationen. Dieser Artikel soll Ihnen einen kleinen Einblick in die Logging-Möglichkeiten bieten.]]></description>
			<content:encoded><![CDATA[<p>Der NQ Core bietet einige einfache Funktionen zum Loggen von Informationen. Dieser Artikel soll Ihnen einen kleinen Einblick in die Logging-Möglichkeiten bieten.</p>
<h2>Grundlagen</h2>
<p>NQ Core bietet zentral Methoden zum Absetzen von Log-Nachrichten aus Services heraus. Eine Nachricht besteht aus folgenden Informationen:</p>
<ul>
<li><strong>Timestamp</strong> der Nachricht</li>
<li><strong>Level</strong></li>
<li><strong>Service-Instanz</strong>, der die Nachricht generiert</li>
<li><strong>Text</strong> der Nachricht</li>
</ul>
<p>Nachrichten sind klassisch in mehrere Levels kategorisiert, je nachdem, wie kritisch die Information ist. Per Konfiguration kann nach einzelnen Levels gefiltert werden, um das Aufkommen an Log-Nachricht auf ein sinnvolles Maß einzuschränken.</p>
<table border="0">
<tbody>
<tr>
<th>Level</th>
<th>Beschreibung</th>
</tr>
<tr>
<td>Error</td>
<td>Unerwartete Fehler, die u.U. die Stabilität der Anwendung beeinträchtigen können.</td>
</tr>
<tr>
<td>Warning</td>
<td>Informative Warnungen über Fehler, die sauber abgefangen werden, aber dennoch erwähnenswert sind. Dieses Level gibt es erst ab NQ Core 0.96.</td>
</tr>
<tr>
<td>Info</td>
<td>Informative Meldungen zu Abläufen in der Anwendung.</td>
</tr>
<tr>
<td>Debug</td>
<td>Meldungen, die v.a. für Entwickler hilfreich sind.</td>
</tr>
</tbody>
</table>
<p>Die Nachrichten werden auf 2 verschiedenen Wegen verteilt:</p>
<ul>
<li>Füllen einer Log-Datei im Benutzerverzeichnis.</li>
<li>Melden von Log-Meldungen über das <em>MessageLogged</em> Event des Service Manager (siehe weiter unten).</li>
</ul>
<h2>Konfiguration</h2>
<p>Die erste Möglichkeit der Konfiguration sind Kommandozeilenparameter, die an die EXE-Datei des NQ Host (nq.exe) übergeben werden können:</p>
<table border="0">
<tbody>
<tr>
<th>Parameter</th>
<th>Beschreibung</th>
</tr>
<tr>
<td>-li</td>
<td>Aktiviert das Schreiben von Info-Log-Messages in die Log-Datei.</td>
</tr>
<tr>
<td>-Li</td>
<td>Aktiviert das Melden von Info-Log-Messages über <em>MessageLogged</em> Event.</td>
</tr>
<tr>
<td>-ld</td>
<td>Aktiviert das Schreiben von Debug-Log-Messages in die Log-Datei.</td>
</tr>
<tr>
<td>-Ld</td>
<td>Aktiviert das Melden von Debug-Log-Messages über <em>MessageLogged</em> Event.</td>
</tr>
</tbody>
</table>
<p>Standardmäßig ist im NQ Core immer das Logging von Error- und Warning-Nachrichten aktiviert, sodass mit den o.g. Parametern lediglich zusätzliche Levels hinzugenommen werden können.</p>
<p>Die Konfiguration der Levels kann auch programmatisch erfolgen, indem die Eigenschaften <em>LogEventFilter</em> bzw. <em>LogFileFilter</em> belegt werden:</p>
<pre class="brush: csharp; title: ; notranslate">
// Events für alle Levels feuern
NQServiceManager.Instance.LogEventFilter = NQLogType.All;

// Nur Error- und Warning-Messages in die Log-Datei schreiben
NQServiceManager.Instance.LogFileFilter = NQLogType.Error | NQLogType.Warning;
</pre>
<p>Mittels Fluent Interface ist sogar eine noch bequemere Konfiguration möglich. Im folgenden Code werden alle Levels außer dem Debug-Level in die Log-Datei geschrieben:</p>
<pre class="brush: csharp; title: ; notranslate">
ServiceCore.Log.FileLevels = NQLogType.All;
ServiceCore.Log.FileLevels -= NQLogType.Debug;
</pre>
<p>Wenn das Logging in die Textdatei aktiviert wurde, wird Pfad und Name im Normalfall vom NQ Core bestimmt. Der Ablageort ist das Windows-Einstellungsverzeichnis des jeweiligen Benutzers, unter Windows 7 beispielsweise</p>
<p><em>C:\Users\&lt;Benutzername&gt;\AppData\Roaming\NQ.&lt;HashDesApplikationsverzeichnisses&gt;.log</em></p>
<p>Der Dateiname enthält einen Hashwert, der aus dem Ausführungspfad der Anwendung berechnet wird. Dies dient der Unterscheidung von Log-Dateien von NQ-basieren Anwendungen, die in verschiedenen Verzeichnissen installiert sind.</p>
<p>Name und Ablageort der Datei können über den Kommandozeilenparameter <em>-lf</em> geändert werden:</p>
<pre class="brush: plain; light: true; title: ; notranslate">
nq.exe -lf C:\EinVerzeichnis\Datei.log
</pre>
<p>Abschließend seien noch Kommandozeilenparameter zeigt, mit denen Logging grundsätzlich deaktiviert werden kann:</p>
<table border="0">
<tbody>
<tr>
<th>Parameter</th>
<th>Beschreibung</th>
</tr>
<tr>
<td>-ln</td>
<td>Vollständiges Deaktivieren der Logging-Funktionalität (per Events und Log-Datei)</td>
</tr>
<tr>
<td>-lni</td>
<td>Deaktivieren des Logging in eine Textdatei auf einem Datenträger. Bei Angabe von <em>-ln</em> muss <em>-lni</em> nicht zusätzlich angegeben werden.</td>
</tr>
</tbody>
</table>
<h2>Ausgabe von Meldungen</h2>
<p>Services können jederzeit Log-Nachrichten ausgeben, indem sie entsprechende Methoden des Service Managers verwenden:</p>
<pre class="brush: csharp; title: ; notranslate">
// Log-Nachricht mit Info-Level
NQServiceManager.Instance.LogMessage(NQLogType.Info, &quot;Das ist eine Info-Nachricht&quot;);

// Log-Nachricht mit Angabe der loggenden Klasse
NQServiceManager.Instance.LogMessage(this, NQLogType.Info, &quot;Das ist eine Info-Nachricht&quot;);
</pre>
<p>Es ist auch möglich, bei Auftreten einer Exception diese direkt zum Generieren einer Log-Nachricht zu übergeben:</p>
<pre class="brush: csharp; title: ; notranslate">
try
{
    // Some code throwing an exception
}
catch (Exception ex)
{
    NQServiceManager.Instance.LogMessage(this, NQLogType.Error, ex);
}
</pre>
<p>Das gleiche ist auch mit dem Fluent Interface möglich:</p>
<pre class="brush: csharp; title: ; notranslate">
// Log-Nachricht mit Info-Level
ServiceCore.Log.Info(&quot;Das ist eine Info-Nachricht&quot;);

// Log-Nachricht mit Angabe der loggenden Klasse
ServiceCore.Log.From&lt;object&gt;(this).Info(&quot;Das ist eine Info-Nachricht&quot;);
</pre>
<pre class="brush: csharp; title: ; notranslate">
try
{
    // Some code throwing an exception
}
catch (Exception ex)
{
    ServiceCore.Log.From&lt;object&gt;(this).Error(ex);
}
</pre>
<h2>Benutzerdefinierte Behandlung von Log-Messages</h2>
<p>Wie bereits erwähnt, ermöglicht der NQ Core Services auch eine eigene Behandlung von Log-Nachrichten. Dazu dient das Event <em>MessageLogged</em>:</p>
<pre class="brush: csharp; title: ; notranslate">
NQServiceManager.Instance.MessageLogged += ServiceManager_MessageLogged;
</pre>
<p>&#8230;</p>
<pre class="brush: csharp; title: ; notranslate">
void ServiceManager_MessageLogged(object sender, NQLogEventArgs e)
{
    // Anzeige einer MessageBox bei Error-Logs
    if (e.LogType == NQLogType.Error)
    {
        MessageBox.Show(e.LogMessage, Application.ProductName,
            MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
    }
}
</pre>
<p>Eine besondere Eigenschaft betrifft die Log-Nachrichten, die vom Service Manager selbst erzeugt werden. Viele dieser Nachrichten werden nämlich schon erzeugt, bevor überhaupt ein Service aktiv wird. Damit Services auch diese Nachrichten mitbekommen, werden sie während der Startup-Phase vorübergehend gecached. Erst wenn alle Single-Instance-Services geladen und aktiv sind, werden diese zwischengespeicherten Nachrichten &#8220;auf einen Schlag&#8221; per <em>MessageLogged</em> Event verteilt.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.awzhome.de/pages/252/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>NQ Core 0.96 verfügbar</title>
		<link>http://www.awzhome.de/pages/254</link>
		<comments>http://www.awzhome.de/pages/254#comments</comments>
		<pubDate>Sat, 08 Oct 2011 14:27:04 +0000</pubDate>
		<dc:creator>Rpinski</dc:creator>
				<category><![CDATA[NQ]]></category>

		<guid isPermaLink="false">http://www.awzhome.de/?p=254</guid>
		<description><![CDATA[Das neue Release 0.96 des NQ Core ist nun über Codeplex und erstmals auch über NuGet zum Download verfügbar. Nach 10 Monaten seit dem letzten Release gab es keine bahnbrechenden Neuerungen, sondern v.a. Detailarbeit.]]></description>
			<content:encoded><![CDATA[<p>Das neue Release <strong>0.96</strong> des NQ Core ist nun über <a href="http://nq.codeplex.com/releases/view/74612">Codeplex</a> und erstmals auch über <a href="http://www.nuget.org/List/Packages/NQ.Core">NuGet</a> zum Download verfügbar. Nach 10 Monaten seit dem letzten Release gab es keine bahnbrechenden Neuerungen, sondern v.a. Detailarbeit:</p>
<ul>
<li>Der NQ GUI Host (<em>nq.exe</em>) basiert nun endlich auch auf WPF. Bisher war es immer noch eine Windows Forms Applikation, was zu Schwierigkeiten mit WPF-Oberflächen führen konnte.</li>
<li>Das inzwischen überflüssige <em>INQService</em> Interface wurde entfernt. Auch der Service Manager enthält keine Sonderbehandlung mehr für dieses Interface.</li>
<li>Verbesserungen an der Fehlertoleranz in den Initialisierungsroutinen des Service Managers.</li>
<li>Der Service Manager füllt nun die Log-Messages, die er während des Startup erzeugt, in einen Cache. Grund: Sie können von Services nicht mit dem <em>MessageLogged</em> Event abgefangen werden, weil die Services zu dem Zeitpunkt noch nicht aktiv sind. Sobald alle Single-Instance-Services initialisiert sind, werden die <em>MessageLogged</em> Events aus dem Cache &#8220;nachgefeuert&#8221;.</li>
<li>Neues Log-Level &#8220;Warning&#8221;.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.awzhome.de/pages/254/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Versionierung und Abhängigkeiten zwischen NQ-Komponenten</title>
		<link>http://www.awzhome.de/pages/249</link>
		<comments>http://www.awzhome.de/pages/249#comments</comments>
		<pubDate>Sun, 25 Sep 2011 22:14:32 +0000</pubDate>
		<dc:creator>Rpinski</dc:creator>
				<category><![CDATA[NQ]]></category>

		<guid isPermaLink="false">http://www.awzhome.de/?p=249</guid>
		<description><![CDATA[Im Einführungsartikel wurde das Komponentenkonzept von NQ vorgestellt. In diesem Beitrag soll es nun um einige fortgeschrittene Features gehen, die mit der Versionierung von Komponenten und der Definition von Abhängigkeiten zwischen Komponenten zu tun haben.]]></description>
			<content:encoded><![CDATA[<p>Im <a title="NQ: Einführung in Services und Komponenten" href="http://www.awzhome.de/pages/176">Einführungsartikel</a> wurde das Komponentenkonzept von NQ vorgestellt. In diesem Beitrag soll es nun um einige fortgeschrittene Features gehen, die mit der Versionierung von Komponenten und der Definition von Abhängigkeiten zwischen Komponenten zu tun haben.</p>
<h2>Versionierung</h2>
<p>Grundsätzlich wertet NQ die gewöhnliche Assembly-Version der Hauptkomponente aus, die wie gewohnt in einer <em>AssemblyInfo.cs</em> definiert wird:</p>
<pre class="brush: csharp; title: ; notranslate">
[assembly: AssemblyVersion(&quot;1.0.0.0&quot;)]
[assembly: NQComponentDefinition(&quot;TestComponent&quot;, DisplayName = &quot;Test Component&quot;)]
</pre>
<p>Wenn die Komponente nun veröffentlicht wird und später Nachfolgeversionen erscheinen, bietet NQ die Möglichkeit, Zusammenhänge zwischen den Versionen herzustellen, indem deren Kompatibilität zueinander dargestellt wird. Nehmen wir also an, die Version 1.0.0.0 unserer fiktiven &#8220;TestComponent&#8221; ist bereits veröffentlicht und es wird eine dazu kompatible Nachfolgeversion 2.0.0.0 definiert:</p>
<pre class="brush: csharp; title: ; notranslate">
[assembly: AssemblyVersion(&quot;2.0.0.0&quot;)]
[assembly: NQComponentDefinition(&quot;TestComponent&quot;, DisplayName = &quot;Test Component&quot;)]
[assembly: NQComponentCompatibility(&quot;1.0.0.0&quot;, NQCondition.Equal)]
</pre>
<p>Mit <em>NQComponentCompatibilityAttribute</em> wird festgelegt, dass Version 2.0.0.0 zu Version 1.0.0.0 kompatibel ist. Mit der Konstante <em>NQConditon.Equal</em> wird der Vergleichsoperator bestimmt, in diesem Fall ist nur 1.0.0.0 kompatibel. Mit folgender Definition macht man dagegen alle Versionen ab (einschließlich) 1.0.0.0 kompatibel zur aktuellen:</p>
<pre class="brush: csharp; title: ; notranslate">
[assembly: NQComponentCompatibility(&quot;1.0.0.0&quot;, NQCondition.Greater | NQCondition.Equal)]
</pre>
<p><em>NQComponentCompatibilityAttribute</em> kann auch mehrfach angewandt werden, um z.B. einen Bereich festzulegen:</p>
<pre class="brush: csharp; title: ; notranslate">
[assembly: NQComponentCompatibility(&quot;1.0.0.0&quot;, NQCondition.Greater | NQCondition.Equal)]
[assembly: NQComponentCompatibility(&quot;2.0.0.0&quot;, NQCondition.Lower)]
</pre>
<p>Der Code definiert nun die Kompatibiltät mit allen Versionen <strong>x</strong> mit 1.0.0.0 &lt;= <strong>x</strong> &lt; 2.0.0.0.</p>
<p>Nun bleibt noch die wichtigste Frage: Wozu sollte die Kompatibilität überhaupt definiert werden? Sinnvoll wird es erst, wenn wir nun die Abhängigkeiten zwischen verschiedenen Komponenten betrachten.</p>
<h2>Abhängigkeiten zwischen Komponenten</h2>
<p>Wenn eine Komponente die Anwesenheit einer anderen (evtl. Fremd-)Komponente erfordert, sollte man als Entwickler Vorkehrungen für den Fall treffen, dass diese auf dem System des Benutzers nicht oder nicht in der passenden Version verfügbar ist. In NQ ist hier eine Angabe der Art &#8220;Komponente1 benötigt Komponente2&#8243; möglich:</p>
<pre class="brush: csharp; title: ; notranslate">
[assembly: NQComponentDefinition(&quot;OtherTestComponent&quot;, DisplayName = &quot;Other Test Component&quot;)]
[assembly: NQComponentRequirement(&quot;TestComponent&quot;)]
</pre>
<p>Es wird die Komponente &#8220;OtherTestComponent&#8221; definiert, die zwingend &#8220;TestComponent&#8221; erfordert. Ist diese nicht vorhanden, wird auch &#8220;OtherTestComponent&#8221; von NQ Core ignoriert. Die darin enthaltenen Services werden nicht im System registriert und stattdessen ein Eintrag im Log abgesetzt.</p>
<p>Wir sprachen anfangs von Versionierung. So ist z.B. der Fall möglich, dass die Komponente in einer bestimmten Version vorliegen muss. <em>NQComponentRequirementAttribute</em> lässt auch diese Angabe zu, optional mit einem Vergleichsoperator:</p>
<pre class="brush: csharp; title: ; notranslate">
[assembly: NQComponentDefinition(&quot;OtherTestComponent&quot;, DisplayName = &quot;Other Test Component&quot;)]
[assembly: NQComponentRequirement(&quot;TestComponent&quot;, Version = &quot;1.0.0.0&quot;, Condition = NQCondition.Equal)]
</pre>
<p>So muss &#8220;TestComponent&#8221; in Version 1.0.0.0 vorliegen, damit &#8220;OtherTestComponent&#8221; geladen werden kann.</p>
<p>Wenn &#8220;TestComponent&#8221; jetzt allerdings in einer Nachfolgeversion 2.0.0.0 installiert wird, haben wir ein Problem. Zwar können wir natürlich definieren, dass jede &#8220;TestComponent&#8221;-Version &gt;= 1.0.0.0 akzeptiert wird, doch birgt dies die Gefahr, dass irgendwann eine inkompatible Version von &#8220;TestComponent&#8221; erscheint, die so nicht im Voraus ausgeschlossen werden kann.</p>
<p>Hier kommt die am Anfang dieses Beitrags vorgestellte Definition von Kompatibilitäten zum Tragen. Erinnern wir uns daran, dass wir festgelegt hatten, dass Version 2.0.0.0 zu Version 1.0.0.0 von &#8220;TestComponent&#8221; kompatibel ist:</p>
<pre class="brush: csharp; title: ; notranslate">
[assembly: AssemblyVersion(&quot;2.0.0.0&quot;)]
[assembly: NQComponentDefinition(&quot;TestComponent&quot;, DisplayName = &quot;Test Component&quot;)]
[assembly: NQComponentCompatibility(&quot;1.0.0.0&quot;, NQCondition.Equal)]
</pre>
<p>Liegt also jetzt Version 2.0.0.0 vor, &#8220;OtherTestComponent&#8221; verlangt aber 1.0.0.0, wird der NQ Core die abhängige Komponente trotzdem laden, da die Kompatibilität zur eigentlich verlangten Version (durch deren Entwickler) gewährleistet wurde.</p>
<h2>Abhängigkeiten von Services zu Komponenten</h2>
<p>Bisher haben wir nur Abhängigkeiten von Komponenten zu anderen Komponenten betrachtet. Am Rande sei noch erwähnt, dass auch für einzelne Services Abhängigkeiten zu Komponenten bzw. deren einzelnen Versionen festgelegt werden können:</p>
<pre class="brush: csharp; title: ; notranslate">
[NQExportedService]
[NQComponentRequirement(&quot;TestComponent&quot;, Version = &quot;1.0.0.0&quot;, Condition = NQCondition.Equal)]
public class SomeServiceClass
{
    public SomeServiceClass()
    {
    }
}
</pre>
<p>Wenn die vom Service verlangte Komponente nicht gefunden wird, wird der Service nicht registriert &#8211; er ist dann für andere Services nicht verfügbar. Alles was bisher zu Komponentenabhängigkeiten gesagt wurde, gilt gleichermaßen auch für Services.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.awzhome.de/pages/249/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>awzBoxes: Leichtgewichtige WPF-Library für flexible Oberflächen</title>
		<link>http://www.awzhome.de/pages/229</link>
		<comments>http://www.awzhome.de/pages/229#comments</comments>
		<pubDate>Sat, 16 Apr 2011 20:42:54 +0000</pubDate>
		<dc:creator>Rpinski</dc:creator>
				<category><![CDATA[dotNET]]></category>

		<guid isPermaLink="false">http://www.awzhome.de/?p=229</guid>
		<description><![CDATA[Flexible Oberflächen mit Unterfenstern, die man mit der Maus anordnen oder seitlich andocken kann, sind seit Jahren in. Dieser Artikel stellt "awzBoxes" vor, eine kleine schlanke WPF-Komponente, welche die Entwicklung solcher Oberflächen unterstützt.]]></description>
			<content:encoded><![CDATA[<p>Flexible Oberflächen mit Unterfenstern, die man mit der Maus anordnen oder seitlich andocken kann, sind seit Jahren in. Gerade bei Entwicklungstools gehört dies zum guten Ton, das beweisen sowohl Visual Studio, als auch Eclipse oder NetBeans. Aber auch für Software aus anderen Bereichen können solche GUI-Konzepte praktisch sein.</p>
<p>Das Nebenprojekt <em>NQ Common Services (NQCS)</em> zu meinem kleinen Microkernel <a title="NQ Projekt" href="http://www.awzhome.de/projects/nq" target="_blank">NQ</a> bietet die Grundlage zum Aufbau einer an Visual Studio angelehnten Oberfläche. Da es sich bei NQCS um ein Open Source Projekt handelt, hatte ich mich ursprünglich für das freie <a href="http://avalondock.codeplex.com/" target="_blank">AvalonDock</a> entschieden, um dies zu realisieren. Diese Komponente ahmt das Visual Studio-GUI recht gut nach (es wird u.a. von <a href="http://www.sharpdevelop.net/" target="_blank">SharpDevelop 4</a> verwendet), hat allerdings immer wieder einzelne Fehler, ist relativ schlecht dokumentiert und hat ein an manchen Stellen recht umständliches Interface, das die Verwendung mit der NQCS-Architektur immer wieder erschwerte.</p>
<p>Was macht also der Entwickler bei einem Hobbyprojekt? Er erfindet das Rad einfach neu, aber so dass es auch wirklich seinen Wünschen entspricht! So entstand die kleine WPF-Komponente <em>awzBoxes</em>, die ich in diesem Artikel erstmals vorstellen möchte.</p>
<h2>Box ist Programm</h2>
<p>Wie der Name des Projekts schon andeutet, ist die <strong>Box</strong> hier die Grundidee des GUI-Aufbaus. Hier ein Screenshot eines mit awzBoxes realisierten Hauptfensters:</p>
<p style="text-align: center;"><a rel="attachment wp-att-232" href="http://www.awzhome.de/pages/229/awzboxes_gui_overview"><img class="aligncenter size-full wp-image-232" title="Hauptfenster mit awzBoxes" src="http://www.awzhome.de/wp-content/uploads/awzboxes_gui_overview.png" alt="" width="641" height="390" /></a></p>
<p>Wie üblich werden <strong>Tabs </strong>zur Untergliederung des Hauptfensters in mehrere Unterfenster verwendet. Im Bild sieht man einen Hauptbereich, in dem Unterfenster neben- und untereinander angeordnet sind. Zudem ist ein weiteres Unterfenster (&#8220;Window 1&#8243;) auf der linken Seite angedockt. Zur Abbildung der Fensteranordnung verwendet awzBoxes eine Hierarchie von Unterobjekten, die im folgenden Screenshot grafisch dargestellt sind:</p>
<p style="text-align: center;"><a rel="attachment wp-att-233" href="http://www.awzhome.de/pages/229/awzboxes_gui_structure"><img class="aligncenter size-full wp-image-233" title="Objektstruktur awzBoxes" src="http://www.awzhome.de/wp-content/uploads/awzboxes_gui_structure.png" alt="" width="641" height="390" /></a></p>
<ul>
<li><strong>BoxWindowContainer: </strong>Der <em>BoxWindowContainer </em>ist das Hauptcontrol von awzBoxes. Dieses wird im Hauptfenster der Anwendung platziert und übernimmt das Hosting der verschiedenen Bereiche des Fensters, Speicherung und Wiederherstellung des Layouts usw.</li>
<li><strong>BoxArea:</strong> Das Hauptfenster ist zunächst in <em>BoxArea </em>Controls untergliedert. Neben dem Hauptbereich sind auch die Seitenleisten, in denen Fenster angedockt werden können, eigene BoxAreas. Der Entwickler kann zur Entwicklungszeit selbst festlegen, auf welchen Seiten des Anwendungsfensters BoxAreas zur Verfügung stehen sollen.</li>
<li><strong>BoxLine:</strong> Zur vertikalen Anordnung ist eine BoxArea in einzelne <em>BoxLine </em>Controls unterteilt. Im oberen Screenshot befindet sich daher &#8220;Window 2&#8243; in einer eigenen BoxLine, die anderen Tabs sind in der oberen BoxLine angeordnet. Da die linke Seitenleiste mit dem einzelnen &#8220;Window 1&#8243; nicht weiter untergliedert ist, befindet sich implizit ebenfalls eine (einzige) BoxLine in diesem Bereich.</li>
<li><strong>Box:</strong> Eine BoxLine enthält nun wiederum mindestens eine <em>Box</em>. Visuell ist die Box vergleichbar mit einem <em>TabControl</em>, das einzelne Tabs verwaltet. Im Screenshot enthält die obere BoxLine entsprechend zwei Boxes. Bei Seitenleisten haben Box Controls zudem die Besonderheit, eine Titelleiste zu tragen (zu sehen am &#8220;Window 1&#8243;).</li>
<li><strong>BoxItem:</strong> Ein <em>BoxItem </em>Objekt ist die kleinste Untergliederungsstufe. Diese repräsentiert ein einzelnes Unterfenster bzw. ein Tab. <em>BoxItem </em>ist selbst kein Control, ihm kann jedoch ein Control zugewiesen werden, welches dann im Innenbereich des Unterfensters dargestellt wird. Die <em>BoxItem </em>Klasse bietet Properties zum Festlegen des Fenstertitels, eines optionalen Icons und weitere Anpassungsmöglichkeiten.</li>
</ul>
<p>Die oben dargestellte Struktur lässt sich initiell komplett in XAML vorbelegen, hier folgt ein entsprechendes Beispiel zu den Screenshots:</p>
<pre class="brush: xml; title: ; notranslate">
&lt;Window x:Class=&quot;AWZhome.awzBoxes.TestApp.MainWindow&quot;
		  xmlns=&quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
		  xmlns:x=&quot;http://schemas.microsoft.com/winfx/2006/xaml&quot;
		  xmlns:box=&quot;clr-namespace:AWZhome.awzBoxes;assembly=awzBoxes&quot;
		  Title=&quot;MainWindow&quot; Height=&quot;622&quot; Width=&quot;961&quot;&gt;
	&lt;Grid&gt;
		&lt;box:BoxWindowContainer x:Name=&quot;BoxWindowContainer&quot;&gt;
			&lt;!-- Setzen der Seitenbereiche --&gt;
			&lt;box:BoxWindowContainer.TopBoxArea&gt;
				&lt;box:BoxArea /&gt;
			&lt;/box:BoxWindowContainer.TopBoxArea&gt;
			&lt;box:BoxWindowContainer.BottomBoxArea&gt;
				&lt;box:BoxArea /&gt;
			&lt;/box:BoxWindowContainer.BottomBoxArea&gt;
			&lt;box:BoxWindowContainer.LeftBoxArea&gt;
				&lt;box:BoxArea&gt;
					&lt;box:BoxLine&gt;
						&lt;box:Box&gt;
							&lt;!-- &quot;Window 1&quot; --&gt;
							&lt;box:BoxItem Name=&quot;Window 1&quot;
										 IsHighlighted=&quot;True&quot;
										 Title=&quot;Window 1&quot;
										 IsChanged=&quot;True&quot;
										 Progress=&quot;50&quot;
										 Icon=&quot;/NewDocumentHS.png&quot;&gt;
								&lt;TextBox&gt;&lt;/TextBox&gt;
							&lt;/box:BoxItem&gt;
						&lt;/box:Box&gt;
					&lt;/box:BoxLine&gt;
				&lt;/box:BoxArea&gt;
			&lt;/box:BoxWindowContainer.LeftBoxArea&gt;
			&lt;box:BoxWindowContainer.RightBoxArea&gt;
				&lt;box:BoxArea /&gt;
			&lt;/box:BoxWindowContainer.RightBoxArea&gt;

			&lt;!-- Hauptbereich des Fensters --&gt;
			&lt;box:BoxArea&gt;
				&lt;box:BoxLine&gt;
					&lt;box:Box&gt;
						&lt;!-- &quot;Fixed Window&quot; --&gt;
						&lt;box:BoxItem Name=&quot;Fixed Window&quot; Title=&quot;Fixed Window&quot; IsClosable=&quot;False&quot;&gt;
							&lt;UniformGrid&gt;
								&lt;Button Click=&quot;Button_Click&quot;&gt;Save layout&lt;/Button&gt;
								&lt;Button Click=&quot;Button_Click_1&quot;&gt;Restore layout&lt;/Button&gt;
							&lt;/UniformGrid&gt;
						&lt;/box:BoxItem&gt;

						&lt;!-- &quot;Window 3&quot; --&gt;
						&lt;box:BoxItem Name=&quot;Window 3&quot; Title=&quot;Window 3&quot;&gt;

						&lt;/box:BoxItem&gt;
					&lt;/box:Box&gt;
					&lt;box:Box&gt;
						&lt;!-- &quot;Other Window&quot; --&gt;
						&lt;box:BoxItem Name=&quot;Other Window&quot; Title=&quot;Other Window&quot;&gt;

						&lt;/box:BoxItem&gt;
					&lt;/box:Box&gt;
				&lt;/box:BoxLine&gt;
				&lt;box:BoxLine&gt;
					&lt;box:Box&gt;
						&lt;!-- &quot;Window 2&quot; --&gt;
						&lt;box:BoxItem Name=&quot;Window 2&quot; Title=&quot;Window 2&quot; Closing=&quot;BoxItem_Closing&quot;&gt;

						&lt;/box:BoxItem&gt;
					&lt;/box:Box&gt;
				&lt;/box:BoxLine&gt;
			&lt;/box:BoxArea&gt;
		&lt;/box:BoxWindowContainer&gt;
	&lt;/Grid&gt;
&lt;/Window&gt;
</pre>
<p>Ein neues Unterfenster in einer eigenen Zeile hinzuzufügen, ist per Code sehr einfach:</p>
<pre class="brush: csharp; title: ; notranslate">
BoxLine newBoxLine = new BoxLine();
Box newBox = new Box();
BoxItem newBoxItem = new BoxItem()
{
	Name = &quot;Window 4&quot;,
	Title = &quot;Window 4 Title&quot;
};

((BoxArea) this.BoxWindowContainer.InnerAreaControl).BoxLines.Add(newBoxLine);
newBoxLine.Boxes.Add(newBox);
newBox.Items.Add(newBoxItem);
</pre>
<h2>Die Maus macht mobil</h2>
<p>Eine Oberfläche wäre nicht flexibel, wenn der Benutzer sie nicht z.B. per Maus vielfältig anpassen könnte. Die von awzBoxes dargestellten Unterfenster lassen sich daher schnell und einfach umordnen:</p>
<p><a rel="attachment wp-att-234" href="http://www.awzhome.de/pages/229/awzboxes_sorting_tabs"><img class="aligncenter size-full wp-image-234" title="Umsortieren von Tabs in awzBoxes" src="http://www.awzhome.de/wp-content/uploads/awzboxes_sorting_tabs.png" alt="" width="255" height="83" /></a></p>
<p>Nicht nur das Umordnen funktioniert, auch das Verschieben der Tabs zwischen den Boxes oder das Andocken an die Seiten funktioniert ähnlich zu Visual Studio und anderen Anwendungen:</p>
<p><a rel="attachment wp-att-235" href="http://www.awzhome.de/pages/229/awzboxes_move_tab"><img class="aligncenter size-full wp-image-235" title="Verschieben/Umdocken von Fenstern in awzBoxes" src="http://www.awzhome.de/wp-content/uploads/awzboxes_move_tab.png" alt="" width="408" height="315" /></a></p>
<p>Durch Setzen der Eigenschaften eines BoxItem Objekts kann bestimmt werden, wo ein Unterfenster angedockt werden darf und wo nicht. Hier nur ein kurzes Beispiel:</p>
<pre class="brush: csharp; title: ; notranslate">
newBoxItem.AllowedDockAreas =
	BoxItemDockDirection.DockInnerArea | BoxItemDockDirection.DockLeft | BoxItemDockDirection.DockRight;
</pre>
<p>Das Beispiel legt fest, dass das Unterfenster nur an der linken oder rechten Seitenleiste bzw. im Innenbereich des Fenster eingehängt werden darf.</p>
<h2>Abschluss</h2>
<p>awzBoxes ist zwar speziell für NQCS entstanden, ist aber davon völlig entkoppelt und kann problemlos direkt in eigenen Anwendungen eingesetzt werden. Allerdings befindet sich die Library momentan in Entwicklung und ist daher nicht als separates Downloadpaket erhältlich. Sie muss vielmehr mit dem gesamten NQ/NQCS Projekt aus dem <a href="http://nq.codeplex.com/SourceControl/list/changesets" target="_blank">Sourcecode Repository</a> auf CodePlex heruntergeladen und selbst kompiliert werden. Im heruntergeladenen ZIP-Archiv ist dabei das Unterverzeichnis <strong>/awzBoxes</strong> von Bedeutung. Darin befindet sich die eigenständige Visual Studio-Solution.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.awzhome.de/pages/229/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

