web-dev-qa-db-fra.com

TextBox Binding TwoWay ne met pas à jour jusqu'à ce que Focus Lost WP7

J'ai une page avec des zones de texte pour la saisie de données. La liaison de la zone de texte est définie sur TwoWay. Les données de mon modèle de vue ne sont mises à jour que si la zone de texte perd le focus. Si je clique sur un bouton, tel que Enregistrer, et que la zone de texte a toujours le focus, les modifications apportées à la zone de texte ne sont pas modifiées dans mon modèle d'affichage lors de l'enregistrement.

Existe-t-il un moyen de faire en sorte que la liaison enregistre la valeur de la zone de texte avant qu'elle ne perd son focus? Ou dois-je faire quelque chose dans l'événement de sauvegarde? 

43
Josh Close

Vous pouvez utiliser le comportement UpdateTextBindingOnPropertyChanged de Prism Library pour WP7 pour mettre à jour la valeur liée lorsque le texte est modifié au lieu d’être perdu dans le focus.

7
Derek Lakin

Je suppose que votre bouton Enregistrer est un ApplicationBarButton (pas un bouton normal). Pour les boutons normaux, cela fonctionnera simplement car ils prendront le focus et donc la liaison de données entrera.

Pour les boutons ApplicationBar au téléphone, c'est un peu différent, car ils ne détournent pas l'attention de l'application cliente. Pour vous assurer que la liaison de données entre en action lorsque vous cliquez sur le bouton Enregistrer, vous pouvez ajouter le code suivant dans votre gestionnaire:

object focusObj = FocusManager.GetFocusedElement();
if (focusObj != null && focusObj is TextBox)
{
    var binding = (focusObj as TextBox).GetBindingExpression(TextBox.TextProperty);
    binding.UpdateSource();
}
56
Stefan Wick MSFT

Téléchargez le livre gratuit de Charles Petzold Programmation Windows Phone 7 . À la page 387, il explique comment procéder.

Fondamentalement, définissez la propriété UpdateSourceTrigger de Binding sur Explicit. Ensuite, dans le rappel TextBox de la TextChanged, mettez à jour la source de liaison.

16
Praetorian

Je vais dans le sens opposé de @Petorian.

Votre TextBox a une valeur par défaut UpdateSourceTrigger de LostFocus. Cela signifie que la valeur n'est transmise à votre propriété ViewModel que .., elle perd le focus.

Vous pouvez définir UpdateSourceTrigger sur PropertyChanged:

<TextBox UpdateSourceTrigger="PropertyChanged" Text="{Binding TextViewModelProperty}" />

De http://msdn.Microsoft.com/en-us/library/system.windows.data.binding.updatesourcetrigger.aspx :

Une des valeurs UpdateSourceTrigger . La valeur par défaut est Default, qui renvoie la valeur par défaut UpdateSourceTrigger de la propriété de dépendance cible . Cependant, la valeur par défaut pour la plupart des les propriétés de dépendance sont PropertyChanged, tandis que le texte propriété a une valeur par défaut de LostFocus.

Gardez à l'esprit que cela signifie que tout ce qui est déclenché par une mise à jour de cette propriété se produira beaucoup plus fréquemment (essentiellement à chaque pression de touche, au lieu d'un "vidage" unique lorsque la variable TextBox perd son focus).

J'espère que cela pourra aider!

7
rrhartjr

Voici une réponse rapide à la solution Microsoft proposée par Derek. Plutôt que de télécharger et de parcourir tous les éléments de Prism, copiez simplement cette classe dans votre projet, puis suivez les étapes suivantes pour l'activer:

UpdateBindingOnPropertyChangedBehviour.cs

using System;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Interactivity;

namespace MyCompany.MyProduct
{
    /// <summary>
    /// Custom behavior that updates the source of a binding on a text box as the text changes.
    /// </summary>
    public class UpdateTextBindingOnPropertyChanged : Behavior<TextBox>
    {
        /// <summary>
        /// Binding expression this behavior is attached to.
        /// </summary>
        private BindingExpression _expression;

        /// <summary>
        /// Called after the behavior is attached to an AssociatedObject.
        /// </summary>
        /// <remarks>
        /// Override this to hook up functionality to the AssociatedObject.
        /// </remarks>
        protected override void OnAttached()
        {
            base.OnAttached();

            // Hook events to change behavior
            _expression = AssociatedObject.GetBindingExpression(TextBox.TextProperty);
            AssociatedObject.TextChanged += OnTextChanged;
        }

        /// <summary>
        /// Called when the behavior is being detached from its AssociatedObject, but before it has actually occurred.
        /// </summary>
        /// <remarks>
        /// Override this to unhook functionality from the AssociatedObject.
        /// </remarks>
        protected override void OnDetaching()
        {
            base.OnDetaching();

            // Un-hook events
            AssociatedObject.TextChanged -= OnTextChanged;
            _expression = null;
        }

        /// <summary>
        /// Updates the source property when the text is changed.
        /// </summary>
        private void OnTextChanged(object sender, EventArgs args)
        {
            _expression.UpdateSource();
        }
    }
}

Il s'agit essentiellement d'une version épurée du code Microsoft Prism 4.1 (consultez le projet Silverlight\Prism.Interactivity si vous souhaitez parcourir le reste).

Maintenant comment l'utiliser:

  1. Ajoutez une référence à l’assemblage System.Windows.Interactivity à votre projet Windows Phone.
  2. Dans chaque page où vous souhaitez utiliser le comportement, ajoutez une référence XAML à Assembly: Xmlns: i = "espace de noms clr: System.Windows.Interactivity; Assembly = System.Windows.Interactivity"
  3. Dans le XAML de chaque zone de texte à laquelle vous voulez appliquer le bahvior (qui a déjà une liaison TwoWay à votre propriété source), ajoutez ce qui suit:

    <i: Interaction.Behaviors>
    <my: UpdateTextBindingOnPropertyChanged />
    </ i: Interaction.Behaviors>

    Remarque: le préfixe "mon:" peut être différent dans votre code. C'est simplement la référence de l'espace de noms où vous avez ajouté la classe de comportement.

6
Tony Wall

essayez de définir la propriété UpdateSourceTrigger sur 'PropertyChanged'

comme ça 

Property="{Binding PropertyBinding, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
5
Rajiv

Je n'ai pas essayé la réponse de @ Praetorian, donc si cela fonctionne bien, faites-le. Sinon, utilisez les deux événements KeyUp AND TextChanged pour mettre à jour la source Binding. 

1
PhilChuang

Ce lien a une solution qui a fonctionné parfaitement dans WinRT. Il hérite de TextBox et ajoute une nouvelle propriété: BindableText. 

http://www.familie-smits.com/post/2012/07/29/UpdateSourceTrigger-in-WinRT.aspx

0
jlo