WPF statt WinForms? Erste Schritte mit XAML

Keine Zeit? Hier die Kurzversion in 30 Sekunden.
- WPF beschreibt die Oberfläche in XAML, WinForms erzeugt sie im Designer-Code.
- Layout läuft über Container wie das Grid statt über feste Pixelpositionen.
- Data Binding verbindet eine Eigenschaft mit der Oberfläche,
INotifyPropertyChangedmeldet Änderungen.- Der Designer in Visual Studio 2008 ist eher mau, man schreibt viel XAML von Hand.
- Die Lernkurve ist steil, aber für neue Projekte lohnt sich ein Blick.
Ich habe in C# bisher fast alles mit WinForms gebaut. Funktioniert, ist vertraut, Button auf Formular ziehen, Doppelklick, fertig. Jetzt wollte ich wissen, was an WPF dran ist, das mit .NET 3.0 gekommen ist. Hier meine ersten Schritte mit Visual Studio 2008, .NET 3.5 und C# 3.0.
Das erste Fenster
Ein neues WPF-Projekt legt ein Window an. Statt Designer-Code gibt es eine XAML-Datei, also XML:
<Window x:Class="WpfHallo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Hallo WPF" Height="170" Width="320">
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBox Grid.Row="0" Margin="0,0,0,5"
Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}" />
<TextBlock Grid.Row="1" Text="{Binding Name}" />
<Button Grid.Row="2" Content="Zurücksetzen" Width="100"
HorizontalAlignment="Left" VerticalAlignment="Top"
Click="Reset_Click" />
</Grid>
</Window>Das Grid ersetzt die festen Koordinaten. Zeilen mit Auto sind so hoch wie der Inhalt, * nimmt den Rest. Zieht man das Fenster größer, wandert alles mit. Bei WinForms musste ich dafür mit Anchor und Dock rumprobieren.
Der Button hat übrigens einen ganz normalen Click-Handler, der im Code-Behind steht. Das Ereignismodell kennt man also von WinForms. Wer will, kann später auf Commands umsteigen, davon habe ich aber noch keine Ahnung. Auffällig ist außerdem, dass ein Button in WPF alles Mögliche enthalten kann, nicht nur Text. Ein Bild oder ein ganzes Layout ist drin, das ist bei WinForms undenkbar gewesen.
Data Binding
Jetzt der Teil, der mich überzeugt hat. Wir brauchen eine Klasse, die ihre Änderungen meldet:
using System.ComponentModel;
public class Person : INotifyPropertyChanged
{
private string name = "";
public string Name
{
get { return name; }
set
{
name = value;
OnPropertyChanged("Name");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string property)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(property));
}
}Und im Code-Behind des Fensters:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new Person();
}
private void Reset_Click(object sender, RoutedEventArgs e)
{
((Person)DataContext).Name = "";
}
}Tippt man etwas in die TextBox, steht es sofort im TextBlock darunter. Ein Klick auf den Button leert beides. Ich habe dafür keine einzige Zeile geschrieben, die ein Control direkt anfasst. Das ist der große Unterschied zu WinForms, wo ich sonst textBox1.Text = ... setze.
Der Gedanke dahinter: Die Oberfläche kennt nur den Namen der Eigenschaft und fragt den DataContext danach. Welches Objekt dahintersteckt, ist ihr egal. Damit lässt sich Logik und Anzeige viel besser trennen, und man kann die Klasse Person ohne Fenster testen. Genau das hat mir bei WinForms immer gefehlt, weil dort alles gern im Formular-Code landet.
Stolpersteine
Ganz ehrlich, es war nicht alles einfach:
- Die Lernkurve ist steil. Grid, Binding, Styles, Templates, das ist viel auf einmal.
- Der Designer in Visual Studio 2008 ist nicht der Rede wert. Ich tippe das meiste direkt in XAML.
- Tippfehler in Binding-Pfaden fallen nicht beim Kompilieren auf. Es passiert einfach nichts, und man sucht.
- Ohne
INotifyPropertyChangedbleibt die Oberfläche stumm, wenn sich Werte im Code ändern. Das habe ich am Anfang vergessen.
Dazu kommt, dass man viele Begriffe neu lernen muss: DataContext, Dependency Properties, Resources. Anfangs hat mich das ziemlich genervt, mit der Zeit ergibt es aber ein stimmiges Bild.
Für ein kleines Werkzeug nehme ich vorerst weiter WinForms, weil es schneller geht. Für etwas Größeres mit viel Oberfläche will ich WPF aber ausprobieren.
Wie sieht es bei euch aus? Schon umgestiegen, oder bleibt ihr bei WinForms?
Beitragsbild: eigene Collage mit Logos von Wikimedia Commons (.NET-Logo (2002): Microsoft), jeweils gemeinfrei; die Marken gehören ihren Inhabern.
Christian Ackermann
Softwareentwickler (C++, C, Java, C#) aus der Oberpfalz, bloggt seit 2001 über Linux, Technik und Kochen.