jenswinter.com
Software Development 24/7

PDC-Blog-Verweigerer

October 29, 2008 07:52 by Jens

Hiermit gebe ich bekannt, dass ich keinerlei PDC Posts schreiben werde. Damit gehöre ich nun also offiziell zur absoluten Minderheit der bloggenden .NET-Community, die nichts über die Geschehnisse der PDC schreibt. :-D


Tags:
Actions: E-mail | Permalink | Comments (2) | Comment RSSRSS comment feed

WPF Toolkit veröffentlicht

October 28, 2008 20:36 by Jens

Das WPF Team hat heute die erste stabile Version des WPF Toolkit veröffentlicht. Das Toolkit enthält unter anderem das WPF DataGrid, ein Kalender-Control und Vorschau-Versionen des Ribbon-Controls und des VisualStateManagers.
Die Projekt-Homepage befindet sich auf CodePlex: http://www.codeplex.com/wpf.

Dort kann auch der Quelltext des Paketes heruntergeladen werden:
http://www.codeplex.com/wpf/Release/ProjectReleases.aspx?ReleaseId=15598

.NET bekommt neues Logo

October 25, 2008 20:37 by Jens

Microsoft spendiert .NET ein neues Logo:

Bzw. als horizontale Variante:

Gefällt mir eigentlich ganz gut. Smile


Tags:
Actions: E-mail | Permalink | Comments (0) | Comment RSSRSS comment feed

Einführung in das Managed Extensibility Framework (Teil 4)

October 9, 2008 20:35 by Jens
Bisherige Artikel der Serie:


Das Beispiel dieser Serie ist noch nicht flexibel genug. Im Hauptfenster ist festgelegt, dass das TabControl drei Seiten enthält:

DataContext = new List<object>
                  {
                      new {Title = "Page 1", Page = Page1},
                      new {Title = "Page 2", Page = Page2},
                      new {Title = "Page 3", Page = Page3}
                  };


Viel besser wäre es doch, wenn eine beliebige Anzahl von Seiten dargestellt werden können.

Das MEF bietet diese Möglichkeit. Es ist in der Lage, mehrere Komponenten, die denselben Contract haben, in eine Collection zu importieren. Das bedeutet zunächst, die Export-Contracts der UserControls müssen angepasst werden, sodass sie alle gleich lauten:

[Export("Page")]
public partial class Page1 : UserControl
{
    public Page1()
    {
        InitializeComponent();
    }
}

[Export("Page")]
public partial class Page2 : UserControl
{
    public Page2()
    {
        InitializeComponent();
    }
}

[Export("Page")]
public partial class Page2 : UserControl
{
    public Page2()
    {
        InitializeComponent();
    }


Diese UserControls können nun in eine Collection importiert werden. Dazu wird die Deklaration der Imports geändert. Die Member "Page1", "Page2" und "Page3" können entfernt werden und durch die Deklaration des Members "Pages" ersetzt werden:

[Import("Page")]
public ExportCollection<UserControl> Pages; 


Dadurch wird der CompositionContainer angewiesen, alle Komponenten mit dem Contract "Page" zu importieren. Über die ExportCollection<T>-Klasse haben wir wieder Zugriff auf die Metadaten der Exports. Die Seiten können nun wie folgt für den DataContext ausgewertet werden:

DataContext = from p in Pages
              select new {Title = p.Metadata["Title"], Page = p.GetExportedObject()};

              
Nun werden beliebig viele UserControls, die mit den entsprechenden Attributen versehen sind, in das TabControl geladen.

Der Quelltext der Beispiel-Anwendung kann hier heruntergeladen werden.

Moderator bei .NET-GUI.com

October 8, 2008 21:12 by Jens


Seit heute gehöre ich dem Moderatoren-Team von .NET-GUI.com an.
Ein herzliches Dankeschön an Norbert Eder für das entgegengebrachte Vertrauen. Gerne werde ich mich den Aufgaben stellen und hoffe, eine Bereicherung für das Team und die Community zu sein.

.NET GUI ist die .NET Community, die sich mit der Entwicklung von grafischen Oberflächen beschäftigt. Gerade mit dem Aufkommen der Windows Presentation Foundation und Silverlight, haben sich viele neue Möglichkeiten ergeben. Der Gestaltung von Oberflächen wird höhere Priorität zuteil. Diese Community bietet die Chance, sich über alle Belange von grafischen Oberflächen auszutauschen. Einzige Einschränkung: Die Basis muss durch das .NET Framework gegeben sein.

Wenn Ihr also Anwendungen mit den Technologien Windows Forms, WPF oder Silverlight entwickelt, so ist .NET-GUI.com die richtige Anlaufstelle für alle Fragen über die Oberflächenprogrammierung. 

Channel8 beim .NET Open Space

October 8, 2008 19:30 by Jens

Also wird es tatsächlich Videos vom .NET Open Space 2008 geben. Woohoo! Rock on!


Kein .NET Open Space 2008 für mich

October 7, 2008 21:02 by Jens

Ich habe heute meine Anmeldung für den .NET Open Space 2008 zurückgezogen. Leider ist mir etwas dazwischen gekommen.
Ich wäre wirklich gerne dabei gewesen.

Ich wünsche allen Teilnehmern viel Spaß. Vielleicht ist ja auch jemand dabei, der ein paar Filmchen dreht. Dann kann ich mich später in eine dunkle Kammer einschließen, die Filme startenund so tun als wäre ich gerade beim Open Space dabei. Muähähä...


Einführung in das Managed Extensibility Framework (Teil 3)

October 7, 2008 20:15 by Jens

Bisherige Artikel der Serie:


Im vorigen Artikel habe ich gezeigt, wie mit Hilfe des MEF einem TabControls Seiten hinzugefügt werden können, ohne dass die Seiten explizit erzeugt werden müssen. Die Aufgabe der Erzeugung übernimmt dabei das MEF.

In diesem Artikel geht es um die Verwendung und Auswertung von Metadaten.
Wenn man sich nochmal den Quelltext des Hauptfensters aus dem letzten Beispiel anschaut, so fällt eine sehr unschöne Sache auf:

public partial class MainWindow : Window
{
    [Import("Page1")]
    public UserControl Page1;

    [Import("Page2")]
    public UserControl Page2;
    
    [Import("Page3")]
    public UserControl Page3;

    public MainWindow()
    {
        InitializeComponent();

        var catalog = new AttributedAssemblyPartCatalog(Assembly.GetExecutingAssembly());
        var container = new CompositionContainer(catalog.CreateResolver());
        container.AddPart(this);
        container.Compose();

        DataContext = new List<object>
                          {
                              new {Title = "Page 1", Page = Page1},
                              new {Title = "Page 2", Page = Page2},
                              new {Title = "Page 3", Page = Page3}
                          };
    }
}

Das Fenster braucht sich zwar nicht mehr um die Herkunft und Erzeugung der Seiten kümmern, muss aber trotzdem wissen, wie die Seiten betitelt werden. Das passt irgendwie nicht zusammen.
Zu sehen ist das ganze beim Zuweisen des DataContext. Die Seiten werden importiert, ohne dass wirklich deren Herkunft bekannt ist, aber die Titel sind fest im Quelltext hinterlegt.

Besser wäre es, wenn die Seiten-Bezeichnungen genauso dynamisch bestimmt werden können, wie die Seiten selbst. Sinnvollerweise sollte jede Seite selbst wissen, wie sie bezeichnet werden soll.
Das Hinterlegen von Meta-Informationen ist mit Hilfe des ExportMetadata-Attributes möglich. Damit können Exports mit Informationen versehen werden, die beim Importieren ausgewertet werden können.

Der Quelltext der Seite Page1 sieht nun so aus:

[Export("Page1")]
[ExportMetadata("Title""Page 1")]
public partial class Page1 : UserControl
{
    public Page1()
    {
        InitializeComponent();
    }
}

Die Klasse Page1 wird hier mit dem ExportMetadata-Attribut versehen, dem ein Schlüssel-Wert-Paar übergeben wird. Der erste Parameter ist der Schlüssel, und lautet in diesem Fall natürlich "Title". Der zweite Parameter ist die tatsächliche Bezeichnung, die im Hauptfenster verwendet werden soll.

Nachdem die anderen Seiten auf dieselbe Weise erweitert wurden, können die Metadaten beim Importieren verwendet werden. Dafür müssen aber zunächst die Imports etwas abgewandelt werden:

[Import("Page1")]
public Export<UserControl> Page1;

[Import("Page2")]
public Export<UserControl> Page2;

[Import("Page3")]
public Export<UserControl> Page3;

Die Seiten sind nun nicht mehr als UserControl deklariert, sondern als Export<UserControl>. Die Export-Klasse verfügt über eine Metadata-Eigenschaft, die mit den entsprechenden Angaben beim Importieren gefüllt werden. Beim Füllen des DataContext können diese Daten dann verwendet werden. An das eigentliche UserControl-Objekt gelangt man über die Methode GetExportedObject():

DataContext = new List<object>
                  {
                      new {Title = Page1.Metadata["Title"], Page = Page1.GetExportedObject()},
                      new {Title = Page2.Metadata["Title"], Page = Page2.GetExportedObject()},
                      new {Title = Page3.Metadata["Title"], Page = Page3.GetExportedObject()}
                  };


Die Anwendung zeigt nach den Änderungen erfreulicherweise noch das gleiche Ergebnis, wie vorher. Allerdings muss das Fenster nun nicht mehr wissen, wie die einzelnen Seiten betitelt werden sollen. Das ist ein großer Schritt in Richtung Erweiterbarkeit.

Der Quelltext der Beispielanwendung kann hier heruntergeladen werden.


SVN Integration bei Codeplex

October 6, 2008 22:31 by Jens

Ich habe heute herausgefunden, dass Codeplex eine SVN-Integration besitzt. Bisher habe ich SVNBridge für den Zugriff auf die Projektquellen verwendet. Das ist nun nicht mehr nötig.
Man kann nun ganz einfach mit solch einer URL auf die Sourcen zugreifen:

https://<Projektname>.svn.codeplex.com/svn

Nice!


Einführung in das Managed Extensibility Framework (Teil 2)

October 5, 2008 22:55 by Jens

Bisherige Artikel der Serie:


Im ersten Artikel dieser Serie ist beschrieben, was das Managed Extensibility Framework ist und welche Möglichkeiten es bietet. In diesem Artikel werde ich eine erste Einführung in die Verwendung des MEF zeigen. Anhand einer einfachen Demo-Anwendung soll der Einsatz demonstriert werden. Programme, die das MEF einsetzen, müssen die Assembly System.ComponentModel.Composition referenzieren. Sie kann hier heruntergeladen werden.

In der Demo-App, einem einfachen WPF-Programm, soll ein TabControl mit bestimmten Seiten gefüllt werden. So sieht das Ergebnis aus:



In einem ersten Schritt zeige ich die Umsetzung ohne den Einsatz von MEF. Die Anwendung besteht aus einem Hauptfenster, welches ein TabControl enthält und drei UserControls, die als Seiten in das TabControl geladen werden.

XAML-Code des Hauptfensters:

<Window x:Class="MefDemoApp.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="500" Width="600">

    <Grid>
        <TabControl ItemsSource="{Binding}" DisplayMemberPath="Title">
            <TabControl.ContentTemplate>
                <DataTemplate>
                    <ContentPresenter Content="{Binding Page}"/>
                </DataTemplate>
            </TabControl.ContentTemplate>
        </TabControl>
    </Grid>
</Window>

CodeBehind des Hauptfensters:

public partial class MainWindow : Window
{
    public UserControl Page1 = new Page1();
    public UserControl Page2 = new Page2();
    public UserControl Page3 = new Page3();

    public MainWindow()
    {
        InitializeComponent();

        DataContext = new List<object>
                          {
                              new {Title = "Page 1", Page = Page1},
                              new {Title = "Page 2", Page = Page2},
                              new {Title = "Page 3", Page = Page3}
                          };
    }
}

Der DataContext des Hauptfensters wird mit einer Liste von anonymen Objekten geladen, die jeweils einen Titel und die entsprechende Seite enthalten. Die Titel-Eigenschaft wird für die Beschriftung des Tabs verwendet. Wie im XAML-Code zu sehen ist, wird die ItemsSource des TabControls an den DataContext gebunden und der Content der Tab-Seiten an die Page-Eigenschaft gebunden.
Die Klassen Page1, Page2 und Page3 sind UserControls mit beliebigem Inhalt.

Ein erstes Problem, das im Quelltext zu sehen ist besteht in der direkten Abhängigkeit zu den UserControls. Die Erzeugung der Seiten mittels new Page1() reduziert die Wartbarkeit und die Erweiterbarkeit. Das Hauptfenster sollte nicht dafür verantwortlich sein, welche Seiten angezeigt werden. Erst recht sollte es die Seiten nicht selbst erzeugen.

Die wichtigsten Bestandteile des MEF sind der Katalog und der CompositionContainer. Der Katalog ist verantwortlich für Bereitstellung von Erweiterungen und der CompositionContainer sorgt für die Erzeugung dieser Erweiterungen und der Erfüllung der Abhängigkeiten.
Eine Erweiterung wird im MEF ComposablePart genannt. Ein ComposablePart enthält ein oder mehrere Komponenten (Exports), die anderen ComposableParts zur Verfügung gestellt werden. Es kann Abhängigkeiten zu anderen ComposableParts definieren. Diese Abhängigkeiten werden Imports genannt. Der CompositionContainer erzeugt ein ComposablePart und füllt die als Import deklarierten Komponenten mit den Komponenten, die als Export deklariert sind. Die Verbindung eines Imports mit einem Export ist möglich, da ein Contract zwischen Import und Export definiert wird. Der CompositionContainer kann über diesen Contract feststellen, welche exportierte Komponente zu welcher importierenden Komponente gemappt werden muss.

Die Deklaration der UserControls sieht bei der Verwendung des MEF nun so aus:

[Import("Page1")]
public UserControl Page1;

[Import("Page2")]
public UserControl Page2;

[Import("Page3")]
public UserControl Page3;

Wie hier zu sehen ist, werden die Instanzen nicht mehr explizit mittels new erzeugt. Stattdessen sind sie mit einem Import-Attribut versehen. Jedes Import-Attribut erthält eine Zeichenkette, die den Contract zum jeweiligen Export darstellt. Der CompositionContainer wird versuchen die Felder, die mit einem Import gekennzeichnet sind, mit einer passenden Komponente zu initialisieren.

Dafür müssen die UserControls natürlich als Export deklariert werden. Der CodeBehind eines UserControls sieht dann so aus:

[Export("Page1")]
public partial class Page1 : UserControl
{
    public Page1()
    {
        InitializeComponent();
    }
}

Die Klasse wird mit dem Export-Attribut versehen. Das Attribut erhält hier die Zeichenkette "Page1". Das ist der Contract, über den Imports mit derselben Bezeichnung verknüpft werden können. Die Contract-Bezeichnung kann im Export-Attribut weggelassen werden. Ist das der Fall, wird der Klassenname als Contract-Bezeichnung verwendet.

Jetzt fehlt eigentlich nur noch die Herstellung der Verbindung zwischen exportierten und importierenden Parts. Diese Aufgabe übernimmt der CompositionContainer. Im folgenden Quelltext ist zu sehen, wie der Konstructor des Hauptfensters erweitert wurde:

public MainWindow()
{
    InitializeComponent();

    var catalog = new AttributedAssemblyPartCatalog(Assembly.GetExecutingAssembly());
    var container = new CompositionContainer(catalog.CreateResolver());
    container.AddPart(this);
    container.Compose();

    DataContext = new List<object>
                      {
                          new {Title = "Page 1", Page = Page1},
                          new {Title = "Page 2", Page = Page2},
                          new {Title = "Page 3", Page = Page3}
                      };
}

Ein spezieller Katalog wird erzeugt, damit Exports und Imports gefunden werden können, die sich in der aktuellen Assembly befinden. Neben dem AttributedAssemblyPartCatalog gibt es noch diese Katalog-Varianten:
  • AttributedTypesPartCatalog - lädt Erweiterungen, die als Typen angegeben wurden
  • AggregatingComposablePartCatalog - fässt mehrere Cataloge zusammeny
  • DirectoryPartCatalog - lädt Erweiterungen aus einem angegebenen Verzeichnis

Der CompositionContainer wird erzeugt und erhält dabei eine ValueResolver-Instanz des Kataloges. Der Container benötigt diesen Resolver um die einzelnen Instanzen der angeforderten Erweiterungen erzeugen zu können. Nun muss nur noch mittels container.AddPart(this) die aktuelle Instanz des Hauptfensters hinzugefügt werden. Jetzt hat der Container alle Informationen um beim Aufruf der Compose()-Methode alle notwendigen Erweiterungen zusammenzusammeln und die Abhängigkeiten zu mit korrekten Instanzen zu füllen.
In dem vorliegenden Beispiel erkennt das MEF, dass die MainWindow-Instanz Parts importiert, die die Contracts "Page1", "Page2" und "Page3" haben. Dem CompositionContainer wurde ein Katalog zur Verfügung gestellt wurde, der ein exportierenden Part für jeden dieser Contracts enthält. Daher kann im Compose()-Aufruf auch das Setzen der einzelnen Seiten stattfinden.

Was haben wir eigentlich erreicht? Ich gebe zu, der Quelltext ist nicht gerade hübscher geworden. Für dieselbe Funktionalität ist er zudem auch noch um einige Zeilen gewachsen. Allerdings haben wir eine direkte Abhängigkeit zu den UserControls etwas "aufgeweicht". Dort wo vorher die Typen und deren Konstruktor-Aufrufe standen, haben wir nun eine Abstrahierung in Form von Kontrakten.

Noch besser ist, dass an dieser Stelle nicht Schluss ist. Das hier gezeigte Beispiel war nur ein kleiner Auschnitt. In folgenden Artikeln werde ich auf die fortgeschritteren Möglichkeiten des MEF eingehen.

Der Quelltext der Beispiel-Anwendung kann hier heruntergeladen werden. 

Einführung in das Managed Extensibility Framework (Teil 1)

September 29, 2008 22:33 by Jens
Anfang September wurde die zweite Preview eines interessantes Projektes des .NET Framework Teams auf Codeplex veröffentlicht. Es handelt sich dabei um das Managed Extensibility Framework (MEF). Die Projekt-Homepage befindet sich unter http://www.codeplex.com/mef.

Das MEF ist ein Framework, welches die Entwicklung von erweiterbaren .NET Anwendungen ermöglicht. Die Wiederverwendung und Erweiterung von Komponenten wird damit in Zukunft um einiges einfacher.
Bisher wurden Anwendungen erweiterbar und dynamisch entwickelt, indem mühselig eine Plugin-Infrastruktur eingebaut werden musste. Große Teile dieser Infrastruktur mussten sich um das dynamische Laden von Assemblies und Type kümmern. Viele Zeilen Quelltext sind geschrieben worden, um per Reflection auf externe Komponenten zuzugreifen.
Mit dem MEF wird dem Entwickler ein Großteil der Arbeit abgenommen.

In einer Artikelserie werde ich in die Verwendung das Managed Extensibility Frameworks einführen.

Was bietet das MEF?

Mit Hilfe des MEF können Anwendungen um Funktionalitäten erweitert werden, die sich in externen Komponenten befinden. Diese Komponenten können wiederum andere externe Komponenten verwenden. Für die Auflösung der Abhängigkeiten sorgt dabei das Framework. Anwendungsentwickler müssen sich also nur noch um die Implementierung der Funktionalitäten kümmern. Das Verknüpfen der Bestandteile wird komplett vom MEF übernommen.

Das Framework verfügt dabei über eine Reihe von Möglichkeiten, die benötigten Komponenten zu finden, einzusammeln und zu laden.

Die Erweiterungen können mit Meta-Informationen versehen werden. Dies erlaubt das Abfrufen und Filtern bestimmter Komponenten.

Im nächsten Artikel werde ich die Funktionsweise und Verwendung anhand einer kleinen Beispielanwendung demonstrieren. 

Hello @DotNetGerman Bloggers

September 29, 2008 21:33 by Jens

Ein herzliches Dankeschön an Alex für die Aufnahme meines Blogs in die Liste der deutschsprachigen .NET Blogger. Die Community Site ist zu erreichen unter http://dotnetgerman.com/.

Die Aufnahme ging übrigens mit dem Hinweis einher, dass bei .NET German Bloggers nur deutschprachige Beiträge gelistet werden sollen. Da ich in Zukunft wieder vermehrt deutschsprachigen Content - ähm, ich meine Inhalt - posten werde, dürfte diese Voraussetzung erfüllt sein. :)


Abhängigkeiten visuell aus Code erzeugen

September 25, 2008 21:42 by Jens
In der deutschsprachigen ALT.NET-Mailingliste ist eine sehr interessante Diskussion über die Erzeugung eines visuellen Abhängigkeitsgraphen aus dem Quelltext heraus entstanden. Der Gedanke, aus bestehendem Quelltext eine Architekturdokumentation generieren zu lassen klingt sehr vielversprechend.

Ralf Westphal schrieb ein Posting, in dem er fragte, wie man ein Fluent API dafür aufbauen könnte. Seine Idee sieht dabei in etwa so aus:

Konfiguration:

DIContainer.Instance
    .Root<IServiceA, ServiceA>()
        .uses<IServiceB, ServiceB>();
        

Dazugehöriger Quelltext:

class ServiceA : IServiceA
{
    private IServiceB _sb;

    public ServiceA()
    {
        _sb = DIContainer.Instance.Get<IServiceB>();
    }
}


Generierung des Graphen:

Bitmap bmp = DIContainer.Instance.DependencyGraph.ToBitmap();


Es gibt nur ein Problem, das ich bei dem Ansatz noch sehe. Es verletzt das DRY-Prinzip. Ralf konnte mich bisher noch nicht restlos vom Gegenteil überzeugen. Die Information der Abhängigkeit ist an zwei Stellen vorhanden. Einmal in der Konfiguration des Containers und ein zweites mal im Quelltext selbst.

Momentan bin ich der Überzeugung, dass man mit Hilfe des Managed Extensibility Frameworks diese Wiederholung der Informationen aufheben könnte. Ich forsche aber noch. :)

MEF is on CodePlex now

September 6, 2008 22:15 by Jens

Today Glenn Block announced that the first source bits of the Managed Extensibility Framework are out on CodePlex now.

This looks like a really interesting project. I think it could be very useful for some projects I'm currently working on. Tonight I'm going to explore the source a little bit. I'm especially interested in how it could be leveraged with Smart Client applications that are based on Prism.

From the project site:

The Managed Extensibility Framework (MEF) is a new library in .NET that enables greater reuse of applications and components. Using MEF, .NET applications can make the shift from being statically compiled to dynamically composed. If you are building extensible applications, extensible frameworks and application extensions, then MEF is for you. 

 


Private beta of StackOverflow.com

August 22, 2008 19:09 by Jens

Yesterday I received my login credentials for the private beta of stackoverflow.com! This is awesome.

I suppose I will spend most of the weekend browsing stackoverflow, asking questions and voting answers. StackOverflow is a social community for software developers. It is being developed by none less than Joel Spolsky and Jeff Atwood.

The concept of StackOverflow is based on questions that can be published by each user. They can be answered by others. All questions and answers can be voted on. This way the users gain reputation points and special badges. This is a very addictive concept.

I already put out a question and I was stunned when I saw it already answered after I refreshed the page. This is ridiculous. No kidding!

This site has huge potential. According to Jeff it will go live at the end of August. Until then you could listen to the stackoverflow podcast at http://blog.stackoverflow.com/.