Silverlight Tipp der Woche: Design-Time Data verwenden

by St. Lange 30. September 2010 22:04

In diesem Tipp geht es um die Verwendung von Design-Time Attributen wie d:DataContext, d:DesignInstance oder d:DesignData, die einem das Arbeiten im Visual Studio Designer ganz schön erleichtern können.

Zusammenfassung

Die Verwendung von Design-Time Attributen erlaubt die Nutzung des Property Explorers beim Erstellen von Datenbindungen im XAML-Code, sowie das Anzeigen von Beispieldaten im Designer zur Design-Zeit. Auf das Verhalten der Silverlight- Anwendung zur Laufzeit haben sie keinen Einfluss.

Beschreibung

Vor Visual Studio 2010 war das Erstellen von Datenbindungen in XAML mehr oder weniger ein Blindflug. Ob man alles richtig eingetippt hat, konnte man letztlich erst nach einem Start der Anwendung überprüfen. Und wenn man keine Daten angezeigt bekam, musste man recht mühsam nach den Ursachen suchen. Auch das Erstellen von Datatemplates war ohne Expression Blend praktisch nicht effizient möglich. Mit dem neuen Visual Studio ist das sehr viel einfacher geworden, wenn man ein paar Formalitäten beachtet.

Das Erstellen für den korrekten XAML-Code eines Databindings kann über Property Explorer durchgeführt werden. Dazu muss man ihm allerdings die Information über den zu bindenden Datentyp geben. Das folgende Beispiel zeigt, was zu tun ist:

<UserControl x:Class="DesignTimeData.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
    xmlns:data="clr-namespace:DesignTimeData"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">
  <Grid x:Name="LayoutRoot" d:DataContext="{d:DesignInstance Type=data:Person}">
    <TextBox Text="{Binding Path=Name, Mode=TwoWay}"/>  
  </Grid>
</UserControl>

Der XML-Namespace d wird standardmäßig angelegt und verweist auf die Design-Time Attribute. Außerdem sorgt die Zeile mc:Ignorable="d" dafür, dass alle Elemente aus diesem Namespace zur Laufzeit ignoriert werden. Damit ist es nun möglich, einem äußeren Element wie hier dem Grid einen DataContext zuzuweisen, der nur zur Designzeit verwendet wird. Im Beispiel sorgt das Attribut DesignInstance dafür, dass dem DataContext eine Instanz des Typs Person zugewiesen wird. Mit diesen Informationen ausgestattet kann der Property Explorer den Datentyp analysieren und beispielsweise zum Binden der Property Text dem Entwickler einen hilfreichen Dialog anbieten:

Der Dialog zeigt die Properties der Klasse Person als mögliche Werte für den Binding Path. Den Dialog erhält man über die rechte Maustaste auf der Property Text im Property Explorer und dann über den Menüpunkt "Apply Data Binding…". Damit kann ein Databinding viel leichter erstellt werden als es bisher möglich war. Es empfiehlt sich also, in allen User-Controls generell im LayoutRoot-Element den Design-Time DataContext auf den zur Laufzeit verwendeten Datentyp zu setzen.

Design-Time Daten

Bei komplexeren Controls wie einem DataGrid kann es zusätzlich hilfreich sein, zur Designzeit ein paar Beispieldaten angezeigt zu bekommen. Dadurch kann beispielsweise das individuelle Layout der Spalten besser angepasst werden.

Im Beispiel gibt es zwei vereinfachte Datenklassen Person und Address, sowie eine Collection von Person Objekten:

public class Person
{
  public string Name { get; set; }
  public DateTime Birthday { get; set; }
  public Address Address { get; set; }
}
 
public class PersonCollection : ObservableCollection<Person>
{ }

public class Address
{
  public string City { get; set; }
}

Mit etwas XAML-Code werden damit die Beispieldaten angelegt:

<data:PersonCollection xmlns:data="clr-namespace:DesignTimeData">
  
  <data:Person Name="Miller" Birthday="1.2.1999">
    <data:Person.Address>
      <data:Address City="Cologne"/>

    </data:Person.Address>
  </data:Person>
 
  <data:Person Name="Baker" Birthday="2.3.1988">
    <data:Person.Address>
      <data:Address City="Berlin"/>
    </data:Person.Address>

  </data:Person>
 
  <data:Person Name="Smith" Birthday="3.4.1977">
    <data:Person.Address>
      <data:Address City="Munich"/>
    </data:Person.Address>
  </data:Person>

 
</data:PersonCollection>

Die Beispieldaten kommen in eine XAML-Datei, die Teil des Projektes ist. Die Build Action dieser Datei muss auf DesignData (oder DesignDataWithDesignTimeCreatableTypes) stehen.

Mit diesen Daten wird nun ein DataGrid wie im folgenden Beispiel versorgt:

<sdk:DataGrid Width="376" Height="138" HorizontalAlignment="Left" Margin="12,96,0,0" VerticalAlignment="Top"
          d:DataContext="{d:DesignData Source=./DesignTimeSampleData.xaml}"
          ItemsSource="{Binding}" AutoGenerateColumns="False">
  <sdk:DataGrid.Columns>
    <sdk:DataGridTextColumn Binding="{Binding Path=Name}" Header="Name" />
    <sdk:DataGridTextColumn Binding="{Binding Path=Birthday, StringFormat='dd.MM.yyy'}" Header="Birthday" />
    <sdk:DataGridTextColumn Binding="{Binding Path=Address.City, Mode=TwoWay}" Header="City" />
  </sdk:DataGrid.Columns>

</sdk:DataGrid>

Der DataContext des DataGrids wird über das Design-Time Attribut DesignData direkt mit den Beispieldaten aus der XAMLDatei verbunden. Als Effekt davon werden die Beispieldaten im Designer angezeigt:

Das ist äußerst praktisch, wenn man beispielsweise die Spalten über Data-Temples layouten möchte, denn ohne eine WYSIWYG-Datenvorschau geht das nur mit sehr sehr viel Übung.

Expression Blend verfügt schon etwas länger über die Möglichkeit, das Layout mit generierten Beispieldaten auszustatten. Das dabei verwendete Verfahren ist aber komplizierter und nutzt dafür u.a. Static Resources. Außerdem werden die Daten dem "echten" DataContext zugwiesen und sind daher auch zur Laufzeit vorhanden. Der Entwickler muss sie also entweder irgendwann wieder aus dem XAML entfernen oder zumindest per Code den DataContext überschreiben.

Das beschriebene Verfahren mit den Design-Time Attributen hat dagegen keine Auswirkungen zur Laufzeit und eignet sich auch sehr gut für Entwickler, die keinen Zugriff auf Blend haben.

Weitere Details finden sich in der MSDN Hilfe.

Das Projekt, mit dem die Screenshots gemacht wurden, ist hier:

DesignTimeData.zip (8 kB)

Hier geht's zum nächsten Tipp.

 
kick it on dotnet-kicks.de

Tags:

Silverlight | WPF

Comments are closed

Powered by BlogEngine.NET 1.6.1.0 - Impressum