Windows Presentation Foundation 4.5 – Bindung an statische Eigenschaften

Im dritten Teil Windows Presentation Foundation 4.5 Serie beschäftigen wir uns mit der Bindung an statischen Eigenschaften. Dies war – ohne Umwege – bis inklusive WPF 4.0 nicht möglich. Da es jedoch immer wieder eine entsprechende Anforderung gibt, wurde dies mit Version 4.5 erweitert und diese Möglichkeit zur Verfügung gestellt.

Um statische Eigenschaften mit einem Two-Way-Binding zu versehen, können statische Ereignisse verwendet werden. Diese müssen sich an eine von zwei Signaturen halten. Die erste Signatur ist wie folgt:

public static event EventHandler MyPropertyChanged;

Dabei ist “MyProperty” mit dem Namen der tatsächlichen Eigenschaft zu ersetzen. Die zweite Möglichkeit besteht in einem generischen Ansatz (der an das Ereignis PropertyChanged aus INotifyPropertyChanged angelehnt ist):

public static event EventHandler<PropertyChangedEventArgs> StaticPropertyChanged;

Wichtig: Zu beachten ist, dass die beiden Möglichkeiten mit unterschiedlichen Ereignis-Argumenten arbeiten. Die erste Variante setzt auf die Klasse EventArgs, Variante 2 auf PropertyChangedEventArgs. Dies ist für eine erfolgreiche Implementierung zu berücksichtigen.

Sehen wir uns die Implementierung einer statischen Klasse StaticSettings mit zwei statischen Eigenschaften Value1 und Value2 an:

#f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper">
#f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet">
   1: #0000ff">public #0000ff">static #0000ff">class StaticSettings

#f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">   2: {

   3:     #0000ff">private #0000ff">static #0000ff">string value1;

#f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">   4:     #0000ff">private #0000ff">static #0000ff">string value2;

   5:  

#f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">   6:     #0000ff">public #0000ff">static #0000ff">string Value1

   7:     {

#f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">   8:         get { #0000ff">return value1; }

   9:         set

#f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">  10:         {

  11:             #0000ff">if (value1 == #0000ff">value)

#f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">  12:                 #0000ff">return;

  13:             value1 = #0000ff">value;

#f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">  14:             RaiseValue1Changed();

  15:         }

#f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">  16:     }

  17:  

#f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">  18:     #0000ff">public #0000ff">static #0000ff">event EventHandler Value1Changed;

  19:  

#f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">  20:     #0000ff">private #0000ff">static #0000ff">void RaiseValue1Changed()

  21:     {

#f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">  22:         EventHandler handler = Value1Changed;

  23:         #0000ff">if (handler != #0000ff">null)

#f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">  24:             handler(#0000ff">null, #0000ff">new EventArgs());

  25:     }

#f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">  26:         

  27:     #0000ff">public #0000ff">static #0000ff">string Value2

#f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">  28:     {

  29:         get { #0000ff">return value2; }

#f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">  30:         set

  31:         {

#f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">  32:             #0000ff">if (value2 == #0000ff">value)

  33:                 #0000ff">return;

#f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">  34:             value2 = #0000ff">value;

  35:             RaiseStaticPropertyChanged("Value2");

#f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">  36:         }

  37:     }

#f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">  38:  

  39:     #0000ff">public #0000ff">static #0000ff">event EventHandler<PropertyChangedEventArgs> StaticPropertyChanged;

#f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">  40:  

  41:     #0000ff">public #0000ff">static #0000ff">void RaiseStaticPropertyChanged(#0000ff">string propertyName)

#f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">  42:     {

  43:         EventHandler<PropertyChangedEventArgs> handler = StaticPropertyChanged;

#f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">  44:         #0000ff">if (handler != #0000ff">null)

  45:             handler(#0000ff">null, #0000ff">new PropertyChangedEventArgs(propertyName));

#f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">  46:     }

  47: }

Dabei wird die Update-Notification der Eigenschaft Value1 nach der ersten Variante, die der Eigenschaft Value2 nach der zweiten Variante implementiert. Welche Variante eingesetzt wird, hängt von der Anzahl der Eigenschaften ab. Variante 1 wird bei mehreren Eigenschaften schnell unübersichtlich, wodurch der generische Ansatz zu bevorzugen ist.

Anschließend erfolgt die Deklaration der View:

#f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; height: 450px; max-height: 450px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper">
#f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet">
   1: <Window x:Class="DevTyr.Wpf45.StaticPropertyBinding.MainWindow"

#f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">   2:         xmlns="schemas.microsoft.com/winfx/2006/xaml/presentation"

   3:         xmlns:x="schemas.microsoft.com/winfx/2006/xaml"

#f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">   4:         xmlns:local="clr-namespace:DevTyr.Wpf45.StaticPropertyBinding"

   5:         Title="DevTyr - WPF 4.5 - Static Property Binding" Height="350" Width="525">

#f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">   6:  

   7:     <Grid>

#f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">   8:         <Grid.ColumnDefinitions>

   9:             <ColumnDefinition Width="Auto" MaxWidth="250"/>

#f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">  10:             <ColumnDefinition Width="*"/>

  11:         </Grid.ColumnDefinitions>

#f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">  12:         

  13:         <Grid.RowDefinitions>

#f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">  14:             <RowDefinition Height="Auto"/>

  15:             <RowDefinition Height="Auto"/>

#f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">  16:             <RowDefinition Height="Auto"/>

  17:             <RowDefinition Height="*"/>

#f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">  18:             <RowDefinition Height="Auto"/>

  19:         </Grid.RowDefinitions>

#f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">  20:         

  21:         <TextBlock Text="PropertyNameChanged"

#f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">  22:                    TextWrapping="Wrap"/>

  23:         <TextBox Text="{Binding Path=(local:StaticSettings.Value1)}"

#f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">  24:                    Grid.Column="1"/>

  25:  

#f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">  26:         <TextBlock Text="StaticPropertyChanged"

  27:                    TextWrapping="Wrap"

#f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">  28:                    Grid.Row="1"/>

  29:         <TextBox Text="{Binding Path=(local:StaticSettings.Value2)}"

#f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">  30:                    Grid.Column="1"

  31:                    Grid.Row="1"/>

#f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">  32:  

  33:         <StackPanel Grid.Row="4"

#f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">  34:                     Grid.ColumnSpan="2"

  35:                     Orientation="Horizontal">

#f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">  36:             <Button Content="Update property values"

  37:                     Click="OnRefreshClick"/>

#f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">  38:             <Button Content="Reset"

  39:                     Click="OnResetClick"/>

#f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">  40:             <Button Content="Show current source data"

  41:                     Click="OnShowDataClick"/>

#f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">  42:         </StackPanel>

  43:         

#f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px">  44:     </Grid>

  45: </Window>

Im Endeffekt wird hier nicht mehr gemacht, als zwei Textfelder (diese haben per Default eine Two-Way-Bindung) mit einer Bindung auf die beiden Eigenschaften der in den Ressourcen definierten Klasse zu versehen.

Wichtig: Zu beachten sind die runden Klammern, die für die Pfadangabe der Bindung verwendet werden. Durch diese “weiß” das Bindungssystem, dass nach dem Schema Klassenname.Eigenschaftsname geparst werden soll. Ohne runde Klammern wird nach dem Schema Eigenschaftsname.Eigenschaftsname verfahren.

Nicht verschrecken sollten folgende beiden Eigenheiten der Developer Preview:

Windows Presentation Foundation 4.5 - Probleme Rendering

Windows Presentation Foundation 4.5 - Probleme Rendering

Trotz der angezeigten Fehler kann die Anwendung trotzdem gestartet werden. Offensichtlich wird die neue Bindungs-Syntax noch nicht erkannt. In den weiteren Versionen wird es hierfür wohl einen entsprechenden Fix bzw. eine Erweiterung geben.

Um das Verhalten testen zu können, finden sich auch einige Schaltflächen auf der Oberfläche (auf die Verwendung von MVVM wird der Einfachheit halber verzichtet).

Hier die Eventhandler:

#f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 400px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper">
#f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet">#0000ff">private #0000ff">void OnRefreshClick(#0000ff">object sender, RoutedEventArgs e)
{
StaticSettings.Value1 = "Updated";
StaticSettings.Value2 = "Updated";
}

#0000ff">private #0000ff">void OnResetClick(#0000ff">object sender, RoutedEventArgs e)
{
StaticSettings.Value1 = "";
StaticSettings.Value2 = "";
}

#0000ff">private #0000ff">void OnShowDataClick(#0000ff">object sender, RoutedEventArgs e)
{
StringBuilder sb = #0000ff">new StringBuilder();
sb.AppendFormat("Value1: {0}\n", StaticSettings.Value1);
sb.AppendFormat("Value2: {0}\n", StaticSettings.Value2);
MessageBox.Show(sb.ToString());
}

Nach einem Start der Anwendung können über die erste Schaltfläche im Hintergrund die Werte der beiden Eigenschaften verändert werden. Wie nachfolgend zu sehen, spiegeln sich diese in der Oberfläche wider. Test bestanden.

Windows Presentation Foundation 4.5 - Binding to static properties

Hinweis: Wer mit der Erweiterung x:Static arbeiten wollte, wird eine Enttäuschung erleben. Hier verhält es sich so, dass die Ereignisse bei der Änderung der Source nicht ausgewertet werden. Dies ist das Standardverhalten und wird auch in WPF 4.5 nicht geändert.

Das hier besprochene Beispiel kann nachfolgend herunter geladen werden.

Veröffentlicht von Norbert Eder

Ich bin ein leidenschaftlicher Softwareentwickler. Mein Wissen und meine Gedanken teile ich nicht nur hier im Blog, sondern auch in Fachartikeln und Büchern.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Cookie-Einstellungen
Auf dieser Website werden Cookie verwendet. Diese werden für den Betrieb der Website benötigt oder helfen uns dabei, die Website zu verbessern.
Alle Cookies zulassen
Auswahl speichern
Individuelle Einstellungen
Individuelle Einstellungen
Dies ist eine Übersicht aller Cookies, die auf der Website verwendet werden. Sie haben die Möglichkeit, individuelle Cookie-Einstellungen vorzunehmen. Geben Sie einzelnen Cookies oder ganzen Gruppen Ihre Einwilligung. Essentielle Cookies lassen sich nicht deaktivieren.
Speichern
Abbrechen
Essenziell (1)
Essenzielle Cookies werden für die grundlegende Funktionalität der Website benötigt.
Cookies anzeigen