dth*_*rpe 5 c# data-binding wpf xaml two-way-binding
我有一个数据绑定设置与转换器,以将一个笨拙的XML源转换为显示和编辑方便的内部类树.一切都非常适合从XML源读取,但我有一段时间试图对内部类进行更改以传播回XML源.
这是使用网站的XAML:
<local:SampleConverter x:Key="SampleConverter" />
<Expander Header="Sample" >
<local:SampleControl
Sample="{Binding Path=XmlSource,
Converter={StaticResource SampleConverter},
Mode=TwoWay}" />
</Expander>
Run Code Online (Sandbox Code Playgroud)
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>
Run Code Online (Sandbox Code Playgroud)
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
}
Run Code Online (Sandbox Code Playgroud)
转换为XmlSource以实现INotifyPropertyChanged的内部类,并在树上发送更改通知,如上面的MyPropertyChanged中的断点所示.
因此,如果数据报告它已经改变,为什么WPF不调用我的转换器的ConvertBack方法?
通过几个类似问题的提示和几乎在这里的答案,我有一个保留绑定的可行解决方案。您可以手动强制绑定更新策略性放置的事件中的源,例如 LostFocus:
private void mycontrol_LostFocus(object sender, RoutedEventArgs e)
{
if (mycontrol.IsModified)
{
var binding = mycontrol.GetBindingExpression(MyControl.SampleProperty);
binding.UpdateSource();
}
}
Run Code Online (Sandbox Code Playgroud)