与转换器的双向数据绑定不会更新源

我有一个数据绑定设置与转换器,以将一个笨拙的XML源转换为显示和编辑方便的内部类树。 一切都非常适合从XML源读取,但我有一段时间试图对内部类进行更改以传播回XML源。

这是使用网站的XAML:

    

XmlSource是父数据绑定对象的CLR读写属性(不是DependencyProperty)。 它是从XSD生成的.NET类型。

SampleConverter实现了IValueConverter 。 调用Convert方法并返回非空数据,但从不调用ConvertBack方法。

SampleControl是一个UserControl,它封装了与Sample数据树的UI交互。 这是XAML看起来像这样:

  [... other stuff ...]        

Sample属性是SampleControl代码中的DependencyProperty:

 public static readonly DependencyProperty SampleProperty = DependencyProperty.Register("Sample", typeof(SampleType), typeof(SampleControl), new PropertyMetadata(new PropertyChangedCallback(OnSampleChanged))); public SampleType Sample { get { return (SampleType)GetValue(SampleProperty); } set { SetValue(SampleProperty, value); } } private static void OnSampleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (e.NewValue != null) { ((INotifyPropertyChanged)e.NewValue).PropertyChanged += ((SampleControl)d).MyPropertyChanged; } else if (e.OldValue != null) { ((INotifyPropertyChanged)e.OldValue).PropertyChanged -= ((SampleControl)d).MyPropertyChanged; } } private void MyPropertyChanged(object sender, PropertyChangedEventArgs e) { ; // breakpoint here shows change notices are happening } 

转换为XmlSource以实现INotifyPropertyChanged的内部类,并在树上发送更改通知,如上面的MyPropertyChanged中的断点所示。

因此,如果数据报告它已经改变,为什么WPF不调用我的转换器的ConvertBack方法?

通过几个类似问题的提示和SO上的几乎答案,我有一个保留绑定的工作解决方案。 您可以手动强制绑定在策略性放置的事件中更新源,例如LostFocus:

 private void mycontrol_LostFocus(object sender, RoutedEventArgs e) { if (mycontrol.IsModified) { var binding = mycontrol.GetBindingExpression(MyControl.SampleProperty); binding.UpdateSource(); } } 

XmlSource是父数据绑定对象的CLR读写属性(不是DependencyProperty)。 它是从XSD生成的.NET类型。

我相信这是你的问题。 基本CLR属性不会通知,因此无法参与双向数据绑定。 我的猜测是你的一次性绑定? 输出窗口中是否有任何数据绑定错误?

您可以尝试创建包含XmlSource属性的类的包装器,使该类实现INotifyPropertyChanged,并将XmlSource公开为通知属性(它不需要是依赖项属性)。

另外,关于这个评论:

您是说数据绑定仅在将新实例分配给Sample属性时才有效,但是如果Sample属性引用的现有实例的属性发生更改并且通过INotifyPropertyChanged发出更改信号,则不会这样做吗?

INotifyPropertyChanged的示例实现通常在属性本身更改时发生通知,而不是在子项或其他属性更改时发生。 但是,您可以随时在任何属性上触发通知事件。 例如,您可能具有“全名”属性,该属性会在“名字”或“姓氏”发生变化时通知。

如果以上内容没有帮助,我建议您发布一些代码 – 可能是您正在努力工作的简化版本。

编辑:

我想我误解了你的问题。 我认为问题是你在评论中提到的 – 它是一种参考类型。 可能值得在你的OnSampleChanged中尝试这个:

 private static void OnSampleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var oldValue = Sample; Sample = new SampleType(); Sample = oldValue; } 

我认为这将迫使绑定系统识别出目标端发生了某些变化。

有类似的问题。 解决方案如下:

而不是单向绑定我使用单向和转换器。 转换器将对象(在您的情况下,xmlsource属性的父对象)转换(封装)到viewModel,并且控件绑定到它。

viewModel的工作方式类似于代理,保存对象的引用,管理它的属性,当然还实现了INotifyPropertyChanged。 在这种情况下,您不需要调用ConvertBack方法,因为操作是通过viewModel在适当的实例上执行的。

所以你有一个干净的视图,你不需要xaml.cs中的任何代码