web-dev-qa-db-fra.com

Liaison bidirectionnelle dans WPF

Je ne peux pas faire fonctionner une liaison bidirectionnelle dans WPF.

J'ai une propriété de chaîne dans la fenêtre principale de mon application qui est liée à une zone de texte (j'ai défini le mode sur "TwoWay").

Le seul moment où la valeur de TextBox sera mise à jour, c'est lorsque la fenêtre s'initialise.

Lorsque je tape dans la TextBox, la valeur des propriétés de chaîne sous-jacentes ne change pas.

Lorsque la valeur de la propriété de chaîne est modifiée par une source externe (un événement sur Click, par exemple, qui réinitialise simplement la valeur de la TextBox), la modification ne se propage pas jusqu'à la TextBox.

Quelles sont les étapes que je dois implémenter pour que la liaison bidirectionnelle fonctionne correctement, même dans cet exemple presque trivial?

29
evizaer

Vous essayez probablement de vous lier à une propriété .net CLR au lieu d'une dépendance WPF dependencyProperty (qui fournit une notification de modification en plus de certaines autres choses).
Pour une propriété CLR normale, vous devez implémenter INotifyPropertyChanged et forcer la mise à jour sur la zone de texte dans le gestionnaire d'événements pour PropertyChanged.

  • Faites donc que votre objet avec la propriété implémente cette interface, déclenchez l'événement dans le setter de propriétés. (Alors maintenant, nous avons une notification de changement de propriété)
  • Assurez-vous que l'objet est défini en tant que propriété DataContext de l'élément/contrôle UI

Cela m'a aussi bouleversé lorsque j'ai commencé à en apprendre davantage sur la liaison de données WPF.

Mise à jour: Eh bien OP, cela aurait été une perte de temps si j'aboyais le mauvais arbre .. de toute façon maintenant puisque vous deviez creuser un peu .. vous vous en souviendrez longtemps. Voici l'extrait de code pour compléter cette réponse. A également constaté que la mise à jour de la zone de texte se produit automatiquement dès que je tabule. Il vous suffit de vous abonner manuellement à l'événement et de mettre à jour l'interface utilisateur si votre objet de datacontext n'est pas celui qui implémente INotifyPropertyChanged.

MyWindow.xaml

<Window x:Class="DataBinding.MyWindow" ...
    Title="MyWindow" Height="300" Width="300">
    <StackPanel x:Name="TopLevelContainer">
        <TextBox x:Name="txtValue"  Background="AliceBlue" Text="{Binding Path=MyDotNetProperty}" />
        <TextBlock TextWrapping="Wrap">We're twin blue boxes bound to the same property.</TextBlock>
        <TextBox x:Name="txtValue2"  Background="AliceBlue" Text="{Binding Path=MyDotNetProperty}" />
    </StackPanel>
</Window>

MyWindow.xaml.cs

public partial class MyWindow : Window, INotifyPropertyChanged
{
    public MyWindow()
    {
        InitializeComponent();
        this.MyDotNetProperty = "Go ahead. Change my value.";
        TopLevelContainer.DataContext = this;
    }

    private string m_sValue;
    public string MyDotNetProperty
    {
        get { return m_sValue; }
        set
        {
            m_sValue = value;
            if (null != this.PropertyChanged)
            {
                PropertyChanged(this, new PropertyChangedEventArgs("MyDotNetProperty"));
            }
        }
    }

    #region INotifyPropertyChanged Members
    public event PropertyChangedEventHandler PropertyChanged;
    #endregion
}
59
Gishu

Je ressens le besoin d'ajouter de la précision:

La liaison de données "bidirectionnelle" est plus que la liaison de données "unidirectionnelle".

La liaison de données "à sens unique" est une liaison d'une source à une propriété de dépendance. La source doit implémenter INotifyProertyChanged, afin d'obtenir la propagation des modifications de la source à la cible.

Pour obtenir le "2 way", donc pour obtenir une propagation de la cible à la source, cela dépend du mode de liaison que vous définissez sur la liaison. Si vous ne définissez aucun BindingMode pour votre liaison, le mode de liaison par défaut sera utilisé, et ce mode par défaut est une caractéristique de votre propriété de dépendance cible.

Exemple:

Une zone de texte liée à une propriété de chaîne, appelée "MyTextProperty". Dans le code, vous liez Textbox.Text DependencyProperty à "MyTextProperty" sur l'objet "MyObject"

-> Liaison "unidirectionnelle": le passeur de "My TextProperty" doit déclencher un événement Property Changed, et "MyObject" doit implémenter INotifyPropertyChanged.

-> "Liaison de données 2 voies": en plus de ce qui est nécessaire pour "One way", bindingMode doit être réglé sur "2 way". Dans ce cas particulier, la propriété Text DependencyProperty pour Textbox a "2 façons" comme mode par défaut, il n'y a donc rien d'autre à faire!

5
flamandier

Nous pourrions avoir besoin de voir le code. Votre propriété de chaîne déclenche-t-elle un événement PropertyChanged? Ou (encore mieux) est-il implémenté en tant que DependencyProperty? Sinon, le TextBox lié ne saura pas quand la valeur change.

Quant à taper dans le TextBox et ne pas voir la valeur de la propriété changer, cela peut être dû au fait que votre TextBox ne perd pas le focus. Par défaut, les TextBoxes liées n'écrivent pas leurs valeurs dans la propriété source jusqu'à ce que le focus quitte le contrôle. Essayez d'en tabuler et de voir si la valeur de la propriété change.

3
Matt Hamilton