In diesem Tipp geht es um das Binden an Properties aus der Code-Behind Klasse eines UserControls.
Zusammenfassung
Wenn der DataContext eines UserControls auf das ViewModel zeigt, kann man mit Hilfe von ElementBinding dennoch einfach auf Properties aus der Code-Behind Klasse zugreifen, indem man das UserControl mit einem Namen versieht.
Beschreibung
Üblicherweise wird der DataContext eines UserConrols auf dessen ViewModel gesetzt. Das ViewModel enthält alle für die Anzeige benötigten Daten und das DataBinding der Unter-Controls bindet ausschließlich gegen das ViewModel.
Es kann aber auch vorkommen, dass ein UserControl selbst Properties implementiert, an die einzelne seiner Unter-Controls binden sollen. Wenn die Property DataContext jedoch auf ein ViewModel gesetzt ist, ist es nicht so ganz offensichtlich, wie denn ein Unter-Control innerhalb von XAML an eine Property aus der Code-Behind Klasse binden könnte. Ein einfacher Trick besteht darin, dem UserControl einen Namen zu geben und dann mit Element-Binding den Bezug zur Code-Bedhind Property herzustellen.
In folgendem Beispiel soll die Property SomeItems aus der Code-Behind Klasse als Datenquelle für eine Listbox dienen. Das UserControl erhält hier den Namen „codeBehind“ und bietet darüber der Listbox Property ItemsSource den Zugriff auf SomeItems.
<UserControl x:Name="codeBehind" x:Class="MyProject.MainPage" … />
<Grid Background="White">
<ListBox ItemsSource="{Binding SomeItems, ElementName=codeBehind}" … />
</Grid>
</UserControl>
Obwohl dieser Weg auch bei WPF und Windows Phone funktioniert, klappt die Tool Unterstützung mit „Apply Data Binding…“ im Property Explorer von Visual Studio 2010 nicht. Es werden nur die Properties der Basisklassen aufgelistet. Bei Blend funktioniert der Property Explorer dagegen korrekt.
Anwendungsbeispiel
Es stellt sich natürlich die Frage, wann man überhaupt an Properties aus einem UserControl binden sollte. Dies ist dann sinnvoll und richtig, wenn das UserControl ein wiederverwendbares Control repräsentiert und unabhängig von der Datenmodellierung einer konkreten Anwendung ist. Ein Beispiel wäre ein UserControl „RichTextEditor“ zum Formatieren von Text. Neben einer RichTextBox enthielt so ein UserControl auch eine Toolbar mit Buttons und ComboBoxes zum Einstellen von Schriftart, Größe etc. Ein solcher RichTextEditor benötigt beispielsweise eine Property EditorFontFamily zum Setzen und Abfragen des Default-Fonts. Damit der RichTextEditor wie ein Control als Teil von anderen UserControls verwendet werden kann, sollten seine Properties DataBinding unterstützen. Dazu müssen sie als Dependency Properties implementiert werden, denn nur Dependency Properties können Target Objekte einer Datenbindung sein. Die Implementierung von EditorFontFamily als Dependency Property sieht wie folgt aus.
public partial class RichTextBox : UserControl
{
public FontFamily EditorFontFamily
{
get { return (FontFamily)GetValue(EditorFontFamilyProperty); }
set { SetValue(EditorFontFamilyProperty, value); }
}
public readonly DependencyProperty EditorFontFamilyProperty =
DependencyProperty.Register("EditorFontFamily", typeof(FontFamily), typeof(RichTextEditor),
new PropertyMetadata("Verdana"));
}
Nun kann RichTextEditor in einem anderen UserControl wie jedes andere Control auch verwendet werden. In
diesem Kontext kann dann EditorFontFamily an eine Property MyFontFamily aus einem ViewModel
gebunden werden.
<UserControl x:Class="MyProject.MyPage" … />
<Grid Background="White">
<my:RichTextEditor EditorFontFamily="{Binding MyFontFamily}" … />
</Grid>
</UserControl>
Damit dies funktioniert muss der DataContext auf das ViewModel des umschließenden Controls MyPage zeigen. Daher kann man nicht einfach im Constructor von RichTextEditor den DataContext auf this setzen.
Innerhalb von RichTextEditor holt sich dessen RichTextBox seine FontFamily aus der Code-Behind Klasse.
<UserControl x:Name="codeBehind" x:Class="MyProject.RichTextEditor"
<Grid>
<!-- … -->
<RichTextBox FontFamily="{Binding EditorFontFamily, ElementName=codeBehind}"… />
<!-- … -->
</Grid>
</UserControl>
Dieses Binden über zwei Stufen ist der einfachste Weg, UserContols als eigenständige Controls wiederzuverwenden, und funktioniert in der beschriebenen Art und Weise ohne zusätzlichen Code in der Code-Behind Datei.
Hier geht's zum nächsten Tipp.