11 votes

La liaison de données ne met pas à jour la propriété lorsque l'on appuie sur Entrée dans une boîte de dialogue avec un bouton par défaut.

Mon réglage est celui décrit ci-dessous :

  • Application WPF 4
  • Cadre MVVM Lite
  • Une fenêtre "Ajouter un élément" est affichée au-dessus de la fenêtre principale en mode dialogue (en utilisant view.ShowDialog() ;)
  • La boîte de dialogue comporte un certain nombre de champs de saisie et le bouton "Enregistrer" dont la propriété IsDefault est définie sur True.
  • Le bouton "Enregistrer" est géré par une liaison avec une commande.
  • La liaison de données est définie entre les champs d'entrée dans le XAML de la vue et les propriétés correspondantes dans le ViewModel (une façon, pour l'interface utilisateur, de mettre à jour le ViewModel, avec Mode=OneWayToSource).

Le problème est que lorsque j'appuie sur la touche Entrée du clavier, la valeur que j'ai fournie dans le dernier champ de saisie n'est pas poussée vers la propriété sous-jacente du ViewModel.

Je pense que cela a quelque chose à voir avec le fait que le champ de saisie n'a pas perdu le focus avant la fermeture de la fenêtre (et donc que toutes les liaisons sont "dissoutes"). À titre de comparaison, si je cliquez sur le bouton "Enregistrer" (au lieu de laisser son clic être géré par la fenêtre lors de la saisie), la valeur es mis à jour dans la propriété. De plus, si j'ajoute (horreur ! horreur !) un gestionnaire d'événement à l'événement Click du bouton, et que j'appelle button.Focus() dans le code-behind, tout fonctionne !

Quel peut être le remède ?

Je ne veux évidemment pas gérer les événements de fermeture de fenêtre, et récupérer "manuellement" les valeurs manquantes... Cela irait à l'encontre du concept MVVM :-(

De meilleures suggestions ?

Merci, Alex

17voto

Rachel Points 49408

Par défaut, un TextBox ne signale à sa source que sa valeur a changé que lorsqu'il perd le focus. Vous pouvez changer cela dans votre liaison en définissant UpdateSourceTrigger=PropertyChanged . Ainsi, le TextBox enverra une notification de mise à jour à sa source lorsque le texte est modifié, au lieu de le faire uniquement lorsqu'il perd le focus.

Si vous ne souhaitez pas envoyer une notification de mise à jour chaque fois qu'une touche est enfoncée, vous pouvez créer un fichier de type AttachedProperty pour mettre à jour la source si vous appuyez sur la touche Entrée.

Voici l'AttachedProperty que j'utilise pour des situations comme celle-ci :

// 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

4voto

Wegged Points 1071

Essayez ça.

{Binding Property,UpdateSourceTrigger=PropertyChanged,Mode=OneWayToSource}

0voto

Andreas Kahler Points 2085

Une astuce simple consiste à déplacer le focus du contrôle, par exemple vers le bouton lui-même. Vous pouvez le faire dans le gestionnaire de clics du bouton, car il sera exécuté avant la commande liée :

    public MyView()
    {
        InitializeComponent();

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

Si vous n'aimez pas avoir du code dans votre vue, vous pouvez aussi le faire dans un comportement que vous ajoutez à votre bouton.

-3voto

bdi Points 41

Il s'agit simplement d'un bug de WPF. (Conception ou implémentation, je ne sais pas.) La mise à jour de la TextBox lors de la perte du focus est le comportement attendu dans la plupart des cas et le bouton par défaut devrait également fonctionner dans les dialogues.

Pour la solution de contournement, je pense que c'est une mauvaise direction pour tempérer avec la TextBox. La meilleure solution est de forcer le focus sur le bouton par défaut.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X