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

时间:2011-06-15 20:24:38

标签: c# wpf xaml data-binding 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>

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

3 个答案:

答案 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中的任何代码