WPF Databinding in Verbindung mit einem Defaultbutton
Vor kurzem ist ein Kollege von mir auf ein kleines Problem mit Databinding gestoßen. Und zwar in Verbindung mit einem Button dessen “IsDefault” Eigenschaft auf True gesetzt ist. Es wurde die Bindingquelle nicht aktualisiert.
Zur Verdeutlichung soll folgendes UI dienen:
Die TextBox für den Username ist über Databinding an die “Username” Eigenschaft des ViewModels angebunden. Bei dem Ok Button ist “IsDefault” auf True gesetzt. Mit Hilfe einiger Traces kann man im Ausgabefenster des Visual Studio sehen, was vom Benutzer eingegeben wurde.
...
public string Username
{
get { return _userName; }
set
{
_userName = value;
Trace.WriteLine(string.Format("Username {0} entered.", _userName));
}
}
...
private void OnOkCommand()
{
Trace.WriteLine("Ok button pressed.");
Trace.WriteLine(string.Format("Current username {0}", _userName));
}
...
Bei einer TextBox die per Databinding angebunden ist, wird die Quelle per Default bei Verlust des Fokus aktualisiert. D.h. die Eigenschaft “UpdateSourceTrigger” des Bindings hat den Wert “LostFocus”. Scheinbar wird beim Auslösen eines Defaultbuttons der Fokus nicht auf diesen Button gesetzt. Es wird dann zwar das Command ausgeführt welches mit dem Button verknüpft ist, aber die Quelle der TextBox wurde nicht aktualisiert.
Es gibt mehrere Möglichkeiten das Problem zu lösen.
- Durch Setzen der “UpdateSourceTrigger” Eigenschaft am Binding auf “PropertyChanged”. Dadurch wird die Quelle bei jeder Veränderung aktualisiert.
- Durch manuelles Setzen des Fokus im Click-Eventhandler des Buttons
- Durch manuelles Aktualisieren des Bindings im Click-Eventhandler des Buttons
Bei Variante zwei muss der entsprechende Code in die Code-Behind Datei der View verlagert werden, da ein direkter Zugriff auf das Button Control notwendig ist:
private void OnOkButtonClick(object sender, RoutedEventArgs e)
{
FocusManager.SetFocusedElement(this, (Button)sender);
}
Den Code für die dritte Lösung könnte man (technisch) auch ins ViewModel packen. Gefällt mir aber nicht, da ich im ViewModel keine Kenntnis von UI Controls haben möchte. Deshalb kommt auch hier die Code-Behind Datei zu Zuge:
private void OnOkButtonClick(object sender, RoutedEventArgs e)
{
TextBox focusedTextBox = Keyboard.FocusedElement as TextBox;
if( null != focusedTextBox )
{
BindingExpression bindingExpression = focusedTextBox.GetBindingExpression(TextBox.TextProperty);
if (null != bindingExpression)
{
bindingExpression.UpdateSource();
}
}
}
Bisher gefällt mir die zweite Variante am Besten. Mir sind auch noch keine Nachteile oder Probleme aufgefallen. Den “richtigen” Code, der beim Auslösen des Defaultbuttons ausgeführt werden soll, kann man im ViewModel lassen. Das Command welches mit dem Button verknüpft ist, wird erst nach dem Click Event ausgeführt.
Weiss zufällig jemand, ob es diesen Effekt mit dem Defaultbutton und LostFocus auch unter WinForms gibt?





