112

I have the need to set a binding in code.

I can't seem to get it right tho.

This is what i have tried:

XAML:

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

Code behind:

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

ViewModel:

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

The property is not updating when i set it.

What am i doing wrong?

H.B.
  • 166,899
  • 29
  • 327
  • 400
Willem
  • 9,166
  • 17
  • 68
  • 92

4 Answers4

216

Replace:

myBinding.Source = ViewModel.SomeString;

with:

myBinding.Source = ViewModel;

Example:

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);

Your source should be just ViewModel, the .SomeString part is evaluated from the Path (the Path can be set by the constructor or by the Path property).

Eliahu Aaron
  • 4,103
  • 5
  • 27
  • 37
Dyppl
  • 12,161
  • 9
  • 47
  • 68
  • 15
    You could also use txtText.SetBinding(TextBox.TextProperty,myBinding) in place of last line just to reduce typing :) – Manish Dubey Mar 12 '15 at 11:42
  • 6
    @ManishDubey The benefit of the static method is that the first parameter is defined as a DependencyObject, so it enables data binding on objects that don't derive from FrameworkElement or FrameworkContentElement (such as Freezables). – FreddyFlares Jul 09 '17 at 12:54
  • Thanks for this. Struggled a bit looking for an example like this – Jesse Roper May 21 '20 at 20:29
  • Great! How do I clear that binding? – Quark Soup Apr 15 '22 at 19:47
12

You need to change source to viewmodel object:

myBinding.Source = viewModelObject;
Eliahu Aaron
  • 4,103
  • 5
  • 27
  • 37
bartosz.lipinski
  • 2,627
  • 2
  • 21
  • 34
2

In addition to the answer of Dyppl, I think it would be nice to place this inside the OnDataContextChanged event:

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);
}

We have also had cases were we just saved the DataContext to a local property and used that to access viewmodel properties. The choice is of course yours, I like this approach because it is more consistent with the rest. You can also add some validation, like null checks. If you actually change your DataContext around, I think it would be nice to also call:

BindingOperations.ClearBinding(myText, TextBlock.TextProperty);

to clear the binding of the old viewmodel (e.oldValue in the event handler).

Eliahu Aaron
  • 4,103
  • 5
  • 27
  • 37
sommmen
  • 6,570
  • 2
  • 30
  • 51
0

Example:

DataContext:

  class ViewModel
  {
    public string SomeString
    {
      get => someString;
      set 
      {
        someString = value;
        OnPropertyChanged(nameof(SomeString));
      }
    }
  }

Create Binding:

  new Binding("SomeString")
  {
    Mode = BindingMode.TwoWay,
    UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
  };
Stepagrus
  • 1,189
  • 1
  • 12
  • 19