当DataContext发生更改时,WPF绑定OneWayToSource将source属性设置为“”

我有一个OneWayToSource绑定,当我设置目标控件的DataContext时,它的行为不像我预期的那样。 源的属性设置为默认值而不是目标控件属性的值。

我在标准WPF窗口中创建了一个非常简单的程序来说明我的问题:

XAML

  

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 ?? "") + ", new value=" + (value ?? "") + ")"); _Text = value; } } } 

TextBox tb以null DataContext开头,因此不希望绑定做任何事情。 因此,如果我在文本框中键入内容,例如“X”,则ViewModel.Text属性保持为null。

如果我然后单击Set DataContext按钮,我希望ViewModel.Text属性设置为TextBox.Text属性的“X”。 而是设置为“”。 当然绑定工作正常,因为如果我在文本框中输入“Y”,在“X”之后,它将ViewModel.Text属性设置为“XY”。

这是一个输出示例(由于评估的顺序,最后两行是反直觉的,但它们肯定都在键入“Y”后立即出现):

TextBox更改为X.
单击“设置DataContext”按钮
ViewModel.Text(旧值= ,新值=)
ViewModel.Text(旧值=,新值= XY)
TextBox更改为XY

为什么在设置DataContext时将ViewModel.Text属性设置为“”而不是“X”?

我究竟做错了什么? 我错过了什么吗? 我误解了绑定方面的问题吗?

编辑 :我原以为输出是:

TextBox更改为X.
单击“设置DataContext”按钮
ViewModel.Text(旧值= ,新值= X
ViewModel.Text(旧值= X ,新值= XY)
TextBox更改为XY

它不是一个bug或perhabs。 微软声称它的设计。 首先键入x然后通过单击Button来终止DataContext,从而为什么TextBox保持x并且您的viewModel.Text属性被新初始化(其为空)。 当在datacontext上更改时,仍会调用getter。 最后你没有机会解决这个问题。

但是你可以使用两种方式让它成为现实。

在这里你将需要UpdateSource如下所示:

  private void Button1_Click(object sender, RoutedEventArgs e) { Debug.Print("'Set DataContext' button clicked"); tb.DataContext = _vm; var bindingExp = tb.GetBindingExpression(TextBox.TextProperty); bingExp.UpdateSource(); } 

TextBox在其TextProperty中有一个Binding,当你设置TextBox的DataContext时,TextBox将更新它的源(viewmodel.Text),无论UpdateSourceTrigger是哪种类型。

据说viewmodel中的第一个输出

ViewModel.Text (old value=, new value=)

不是由UpdateSourceTrigger=PropertyChanged触发的。

这只是一个init的过程:

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

因为它不是由UpdateSourceTrigger=PropertyChanged触发的,所以viewmodel将不知道TextBox.Text的值。

当您键入“Y”时,PropertyChanged的触发器将起作用,因此viewmodel读取TextBox的文本。

.NET 4中有一个错误,它有一种方法来源代码绑定,它为OneWayToSource绑定调用getter,这就是为什么你遇到这个问题。你可以通过在tb.DataContext = _vm上放置断点来validation它。 你会发现setter被调用,就在这个getter被调用Text属性之后。你可以通过在分配datacontext之前手动从视图中提供viewmodel值来解决你的问题.NET 4.5解决了这个问题。 看到这里和这里

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