2011-09-09 9 views
7

La mia impostazione è come descritto di seguito:associazione dei dati non aggiorna la proprietà quando si preme Invio su una finestra con un pulsante predefinito

  • WPF 4 applicazione
  • MVVM Lite quadro
  • Un "Add Item "finestra viene visualizzata nella parte superiore della finestra principale in modalità di dialogo (utilizzando view.ShowDialog();)
  • La finestra di dialogo ha un numero di campi di input e il pulsante" Salva "con la proprietà IsDefault impostata su True
  • Il pulsante "Salva" è a portata di mano condotto utilizzando un legame con un collegamento di comando
  • dati è definita tra i campi nel XAML di vista e le proprietà corrispondenti nella ViewModel (unidirezionale, per l'interfaccia utente per aggiornare il ViewModel, con Mode = OneWayToSource)

Il problema è che quando premo Invio sulla tastiera, il valore che ho fornito nell'ultimo campo di input non viene trasferito alla proprietà sottostante di ViewModel.

Sospetto che ciò abbia a che fare con il fatto che il campo di immissione non ha perso il fuoco prima che la finestra sia chiusa (e quindi tutti i binding sono "disciolti"). Per il confronto, se io clic su il pulsante "Salva" (invece di lasciare che il suo Click sia gestito dalla finestra su Invio), il valore è aggiornato nella proprietà. Inoltre, se aggiungo (horror! Horror!) Un gestore di eventi all'evento Click del pulsante e chiamo button.Focus() nel code-behind, tutto funziona!

Quale può essere il rimedio?

Io, ovviamente, non voglio gestire tutti gli eventi di chiusura della finestra, e "manualmente" recuperare i valori mancanti ... Questo violerebbe l'intero concetto MVVM :-(

Eventuali suggerimenti migliori?

Grazie, Alex

+0

Ho riscontrato questo stesso comportamento anche in un certo numero di altre lingue, in particolare Delphi (presumo che Hejlsberg considerasse questa caratteristica non un difetto, se fosse anche lui responsabile di WPF). L'opzione PropertyChanged ha problemi se ti colleghi a un numero, perché proverà a convalidare "3." mentre digiti in Pi e generi un'eccezione. Non mi interessa l'opzione button.Focus() in quanto funzionerà con tutti i controlli e anche a prova di futuro la finestra di dialogo. –

risposta

12

Per impostazione predefinita, a TextBox viene notificata solo la fonte che il suo valore è cambiato una volta che perde lo stato attivo. Puoi cambiarlo nel tuo binding impostando UpdateSourceTrigger=PropertyChanged. Questo farà sì che il TextBox invii una notifica di aggiornamento alla sua origine, il cui testo viene modificato invece che solo quando perde lo stato attivo.

Se non si desidera inviare una notifica di aggiornamento ogni volta che si preme un tasto, è possibile creare un AttachedProperty per aggiornare l'origine se si preme il tasto Invio.

Ecco l'AttachedProperty che uso per situazioni come questa:

// When set to True, Enter Key will update Source 
#region EnterUpdatesTextSource DependencyProperty 

// Property to determine if the Enter key should update the source. Default is False 
public static readonly DependencyProperty EnterUpdatesTextSourceProperty = 
    DependencyProperty.RegisterAttached("EnterUpdatesTextSource", typeof (bool), 
             typeof (TextBoxHelper), 
             new PropertyMetadata(false, EnterUpdatesTextSourcePropertyChanged)); 

// Get 
public static bool GetEnterUpdatesTextSource(DependencyObject obj) 
{ 
    return (bool) obj.GetValue(EnterUpdatesTextSourceProperty); 
} 

// Set 
public static void SetEnterUpdatesTextSource(DependencyObject obj, bool value) 
{ 
    obj.SetValue(EnterUpdatesTextSourceProperty, value); 
} 

// Changed Event - Attach PreviewKeyDown handler 
private static void EnterUpdatesTextSourcePropertyChanged(DependencyObject obj, 
                  DependencyPropertyChangedEventArgs e) 
{ 
    var sender = obj as UIElement; 
    if (obj != null) 
    { 
     if ((bool) e.NewValue) 
     { 
      sender.PreviewKeyDown += OnPreviewKeyDownUpdateSourceIfEnter; 
     } 
     else 
     { 
      sender.PreviewKeyDown -= OnPreviewKeyDownUpdateSourceIfEnter; 
     } 
    } 
} 

// If key being pressed is the Enter key, and EnterUpdatesTextSource is set to true, then update source for Text property 
private static void OnPreviewKeyDownUpdateSourceIfEnter(object sender, KeyEventArgs e) 
{ 
    if (e.Key == Key.Enter) 
    { 
     if (GetEnterUpdatesTextSource((DependencyObject) sender)) 
     { 
      var obj = sender as UIElement; 
      BindingExpression textBinding = BindingOperations.GetBindingExpression(
       obj, TextBox.TextProperty); 

      if (textBinding != null) 
       textBinding.UpdateSource(); 
     } 
    } 
} 

#endregion //EnterUpdatesTextSource DependencyProperty 
3

Prova questo.

{Binding proprietà, UpdateSourceTrigger = PropertyChanged, Mode = OneWayToSource}

-3

Si tratta semplicemente di un bug WPF. (Progettazione o implementazione, non lo so.) L'aggiornamento di TextBox su focus perso è il comportamento previsto nella maggior parte dei casi e anche il pulsante predefinito dovrebbe funzionare nelle finestre di dialogo.

Per risolvere il problema, penso che sia una direzione sbagliata da moderare con il TextBox. La soluzione migliore è forzare la messa a fuoco sul pulsante predefinito.

0

Un semplice trucco è spostare il fuoco lontano dal controllo, ad es. al pulsante stesso. È possibile farlo nell'evento Click gestore del tasto, in quanto verrà eseguito prima del comando legato:

public MyView() 
    { 
     InitializeComponent(); 

     _button.Click += delegate 
     { 
      _button.Focus(); 
     }; 
    } 

Se non piace codice dietro a suo avviso, si può anche fare questo in un comportamento che aggiungi al tuo pulsante.

Problemi correlati