Como definir uma vinculação no código?

96

Tenho a necessidade de definir um enlace no código.

Parece que não consigo acertar.

Isso é o que eu tentei:

XAML:

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

Código por trás:

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

A propriedade não está sendo atualizada quando a configuro.

O que estou fazendo de errado?

Willem
fonte

Respostas:

193

Substituir:

myBinding.Source = ViewModel.SomeString;

com:

myBinding.Source = ViewModel;

Exemplo:

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

Sua fonte deve ser justa ViewModel, a .SomeStringparte é avaliada a partir do Path(o Pathpode ser definido pelo construtor ou pela Pathpropriedade).

Dyppl
fonte
14
Você também pode usar txtText.SetBinding (TextBox.TextProperty, myBinding) no lugar da última linha apenas para reduzir a digitação :)
Manish Dubey
5
@ManishDubey O benefício do método estático é que o primeiro parâmetro é definido como DependencyObject, portanto, permite a vinculação de dados em objetos que não derivam de FrameworkElement ou FrameworkContentElement (como Freezables).
FreddyFlares
Obrigado por isso. Tive dificuldade em encontrar um exemplo como este
Jesse Roper
11

Você precisa alterar a fonte para o objeto viewmodel:

myBinding.Source = viewModelObject;
Baalazamon
fonte
1

Além da resposta do Dyppl , acho que seria bom colocar isso dentro do OnDataContextChangedevento:

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

Também tivemos casos em que apenas salvamos o DataContextem uma propriedade local e usamos isso para acessar as propriedades do viewmodel. A escolha é naturalmente sua, gosto dessa abordagem porque é mais consistente com as demais. Você também pode adicionar alguma validação, como verificações de nulos. Se você realmente mudar de posição DataContext, acho que seria bom também chamar:

BindingOperations.ClearBinding(myText, TextBlock.TextProperty);

para limpar a vinculação do modelo de visão antigo ( e.oldValueno manipulador de eventos).

sommmen
fonte