Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF binding OneWayToSource sets source property to "" when the DataContext is changed

Tags:

c#

binding

wpf

xaml

I have a OneWayToSource binding that is not behaving as I expected when I set the DataContext of the target control. The property of the source is being set to default instead of the value of the target control's property.

I've created a very simple program in a standard WPF window that illustrates my problem:

XAML

<StackPanel>
  <TextBox x:Name="tb"
    Text="{Binding Path=Text,Mode=OneWayToSource,UpdateSourceTrigger=PropertyChanged}"
    TextChanged="TextBox_TextChanged"/>

  <Button Content="Set DataContext" Click="Button1_Click"/>
</StackPanel>

MainWindow.cs

public partial class MainWindow : Window
{
   private ViewModel _vm = new ViewModel();

   private void Button1_Click(object sender, RoutedEventArgs e)
   {
      Debug.Print("'Set DataContext' button clicked");
      tb.DataContext = _vm;
   }

   private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
   {
      Debug.Print("TextBox changed to " + tb.Text);
   }
}

ViewModel.cs

public class ViewModel
{
   private string _Text;
   public string Text
   {
      get { return _Text; }
      set
      {
         Debug.Print(
            "ViewModel.Text (old value=" + (_Text ?? "<null>") + 
            ", new value=" + (value ?? "<null>") + ")");
         _Text = value;
      }
   }
}

The TextBox tb starts out with a null DataContext and therefore the binding is not expected to do anything. So if I type something in the text box, say "X", the ViewModel.Text property remains null.

If I then click the Set DataContext button I would have expected the ViewModel.Text property to be set to the "X" of the TextBox.Text property. Instead it is set to "". Certainly the binding is working because if I then type "Y" in the text box, after the "X", it sets the ViewModel.Text property to "XY".

Here is an example of the output (the last two lines are counter-intuitive because of the order of evaluation, but they definitely both occur immediately after typing the "Y"):

TextBox changed to X
'Set DataContext' button clicked
ViewModel.Text (old value=<null>, new value=)
ViewModel.Text (old value=, new value=XY)
TextBox changed to XY

Why is the ViewModel.Text property being set to "" instead of "X" when the DataContext is set?

What am I doing wrong? Am I missing something? Have I misunderstood something about binding?

Edit: I would have expected the output to be:

TextBox changed to X
'Set DataContext' button clicked
ViewModel.Text (old value=<null>, new value=X)
ViewModel.Text (old value=X, new value=XY)
TextBox changed to XY

like image 817
stritch000 Avatar asked Oct 31 '22 21:10

stritch000


1 Answers

Its a bug or perhabs not. Microsoft claims its by design. You first type x and then you kill DataContext by clicking on Button hence why the TextBox holds x and your viewModel.Text property gets newly initialized (its empty). When on datacontext changed getter will still be called. In the end you have no chance to fix this.

You can however use two way and let it be.

like image 117
dev hedgehog Avatar answered Nov 12 '22 21:11

dev hedgehog