我已经使用转换器设置了数据绑定,以便将一个笨拙的XML源转换为内部类的显示和编辑方便的树。一切都非常适合从XML源读取,但我有一段时间试图对内部类进行更改以传播回XML源。
这是使用网站的XAML:
<local:SampleConverter x:Key="SampleConverter" />
<Expander Header="Sample" >
<local:SampleControl
Sample="{Binding Path=XmlSource,
Converter={StaticResource SampleConverter},
Mode=TwoWay}" />
</Expander>
XmlSource是父数据绑定对象的CLR读写属性(不是DependencyProperty)。它是从XSD生成的.NET类型。
SampleConverter实现IValueConverter
。调用Convert
方法并返回非空数据,但永远不会调用ConvertBack
方法。
SampleControl是一个UserControl,它封装了与Sample数据树的UI交互。这是XAML看起来像这样:
<UserControl x:Class="SampleControl">
[... other stuff ...]
<UserControl.Content>
<Binding Path="Sample" RelativeSource="{RelativeSource Mode=Self}" Mode="TwoWay" TargetNullValue="{StaticResource EmptySampleText}" />
</UserControl.Content>
<UserControl.ContentTemplateSelector>
<local:BoxedItemTemplateSelector />
</UserControl.ContentTemplateSelector>
</UserControl>
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方法?
答案 0 :(得分:2)
通过几个类似问题的提示和SO的几乎答案,我有一个保留绑定的工作解决方案。您可以手动强制绑定在策略性放置的事件中更新源,例如LostFocus:
private void mycontrol_LostFocus(object sender, RoutedEventArgs e)
{
if (mycontrol.IsModified)
{
var binding = mycontrol.GetBindingExpression(MyControl.SampleProperty);
binding.UpdateSource();
}
}
答案 1 :(得分:0)
XmlSource是一个CLR读写属性 父级的(不是DependencyProperty) 数据绑定对象。它是.NET类型 从XSD生成。
我相信这是你的问题。基本CLR属性不会通知,因此无法参与双向数据绑定。我的猜测是你的一次性绑定?您的输出窗口中是否有任何数据绑定错误?
您可以尝试创建一个包含XmlSource属性类的包装器,使该类实现INotifyPropertyChanged,并将XmlSource公开为通知属性(它不需要是依赖属性)。
另外,关于这个评论:
您是说仅限数据绑定 如果分配了新实例,则有效 Sample属性,但不是if 现有实例的属性 Sample属性引用的是 通过改变并发出变化信号 INotifyPropertyChanged的?
INotifyPropertyChanged的示例实现通常会在属性本身更改时发生通知,而不是在子项或其他属性发生更改时。但是,您可以随时在任何属性上触发通知事件。例如,您可能有一个“全名”属性,只要“名字”或“姓氏”发生变化就会通知。
如果以上内容没有帮助,我建议您发布一些代码 - 可能是您正在努力工作的简化版本。
修改强>
我想我误解了你的问题。我认为问题是你在评论中提到的 - 它是一种参考类型。可能值得在OnSampleChanged中尝试这个:
private static void OnSampleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var oldValue = Sample;
Sample = new SampleType();
Sample = oldValue;
}
我认为这将迫使绑定系统识别出目标端发生了某些变化。
答案 2 :(得分:0)
有类似的问题。解决方案如下:
而不是双向绑定我使用单向和转换器。 转换器将对象(在您的情况下,xmlsource属性的父对象)转换(封装)到viewModel,并且控件绑定到它。
viewModel的工作方式类似于代理,包含对象的引用,管理它的属性,当然还实现了INotifyPropertyChanged。 在这种情况下,您不需要调用ConvertBack方法,因为操作是通过viewModel在适当的实例上执行的。
所以你有一个干净的视图,你不需要xaml.cs中的任何代码