Comment définir une liaison dans le code?

97

J'ai besoin de définir une liaison dans le code.

Je n'arrive pas à faire les choses correctement.

Voici ce que j'ai essayé:

XAML:

<TextBox Name="txtText"></TextBox>

Code derrière:

Binding myBinding = new Binding("SomeString");
myBinding.Source = ViewModel.SomeString;
myBinding.Mode = BindingMode.TwoWay;
myBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
BindingOperations.SetBinding(txtText, TextBox.TextProperty, myBinding);

VoirModèle:

public string SomeString
    {
      get
      { 
          return someString;
      }
      set 
      { 
          someString= value;
          OnPropertyChanged("SomeString");
      }
    }

La propriété ne se met pas à jour lorsque je la définis.

Qu'est-ce que je fais mal?

Willem
la source

Réponses:

194

Remplacer:

myBinding.Source = ViewModel.SomeString;

avec:

myBinding.Source = ViewModel;

Exemple:

Binding myBinding = new Binding();
myBinding.Source = ViewModel;
myBinding.Path = new PropertyPath("SomeString");
myBinding.Mode = BindingMode.TwoWay;
myBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
BindingOperations.SetBinding(txtText, TextBox.TextProperty, myBinding);

Votre source doit être juste ViewModel, la .SomeStringpièce est évaluée à partir du Path(le Pathpeut être défini par le constructeur ou par la Pathpropriété).

Dyppl
la source
14
Vous pouvez également utiliser txtText.SetBinding (TextBox.TextProperty, myBinding) à la place de la dernière ligne juste pour réduire la frappe :)
Manish Dubey
5
@ManishDubey L'avantage de la méthode statique est que le premier paramètre est défini en tant que DependencyObject, ce qui permet la liaison de données sur des objets qui ne dérivent pas de FrameworkElement ou FrameworkContentElement (tels que Freezables).
FreddyFlares
Merci pour cela. J'ai eu un peu de mal à chercher un exemple comme celui-ci
Jesse Roper
12

Vous devez changer la source en objet viewmodel:

myBinding.Source = viewModelObject;
bartosz.lipinski
la source
2

En plus de la réponse de Dyppl , je pense que ce serait bien de placer ceci à l'intérieur de l' OnDataContextChangedévénement:

private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
    // Unforunately we cannot bind from the viewmodel to the code behind so easily, the dependency property is not available in XAML. (for some reason).
    // To work around this, we create the binding once we get the viewmodel through the datacontext.
    var newViewModel = e.NewValue as MyViewModel;

    var executablePathBinding = new Binding
    {
        Source = newViewModel,
        Path = new PropertyPath(nameof(newViewModel.ExecutablePath))
    };

    BindingOperations.SetBinding(LayoutRoot, ExecutablePathProperty, executablePathBinding);
}

Nous avons également eu des cas où nous avons simplement enregistré le DataContextdans une propriété locale et l' avons utilisé pour accéder aux propriétés de viewmodel. Le choix vous appartient bien sûr, j'aime cette approche car elle est plus cohérente avec le reste. Vous pouvez également ajouter des validations, comme des vérifications nulles. Si vous changez réellement votre DataContextentourage, je pense que ce serait bien d'appeler également:

BindingOperations.ClearBinding(myText, TextBlock.TextProperty);

pour effacer la liaison de l'ancien viewmodel ( e.oldValuedans le gestionnaire d'événements).

sommmen
la source