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

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方法?

dth*_*rpe 2

通过几个类似问题的提示和几乎在这里的答案,我有一个保留绑定的可行解决方案。您可以手动强制绑定更新策略性放置的事件中的源,例如 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)