与转换器的双向数据绑定不会更新源 [英] Two-way data binding with converter doesn't update source

查看:150
本文介绍了与转换器的双向数据绑定不会更新源的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个数据绑定设置与一个转换器,将一个尴尬的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 。调用转换方法,并返回非空数据,但从未调用 ConvertBack 方法。



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

 < UserControl x:Class =SampleControl> 
[...其他东西...]

< UserControl.Content>
< Binding Path =SampleRelativeSource ={RelativeSource Mode = Self}Mode =TwoWayTargetNullValue ={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)
{
; //这里的断点显示更改通知正在发生
}

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();
}
}


I've got a data binding set up with a converter to transform an awkward XML source to a display- and editing- convenient tree of internal classes. Everything works great for reading from the XML source, but I'm having a devil of a time trying to get changes made to the internal classes to propagate back to the XML source.

Here's the XAML for the use site:

        <local:SampleConverter x:Key="SampleConverter" />
        <Expander Header="Sample" >
            <local:SampleControl 
                Sample="{Binding Path=XmlSource, 
                                 Converter={StaticResource SampleConverter}, 
                                 Mode=TwoWay}" />
        </Expander>

XmlSource is a CLR read-write property (not DependencyProperty) of the parent data bound object. It is a .NET type generated from an XSD.

SampleConverter implements IValueConverter. The Convert method is called and returns non-null data, but the ConvertBack method is never called.

SampleControl is a UserControl that encapsulates UI interaction with the Sample data tree. It's XAML looks like this:

<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>

The Sample property is a DependencyProperty in the SampleControl code behind:

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
}

The internal classes that the XmlSource is converted to implement INotifyPropertyChanged, and are sending change notifications up the tree, as indicated by a breakpoint in MyPropertyChanged above.

So if the data is reporting that it has changed, why isn't WPF calling my converter's ConvertBack method?

解决方案

With hints from several similar questions and almost answers here on SO, I have a working solution that preserves the binding. You can manually force the binding to update the source in a strategically placed event, such as LostFocus:

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

这篇关于与转换器的双向数据绑定不会更新源的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆