2011-06-15 50 views
5

我有一个数据绑定设置与转换器将一个尴尬的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> 

样品属性在后面的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

属性更改您的代码示例仅表示该样品的特性正在发生变化,而不是样品本身。 – Ragepotato 2011-06-15 20:52:30

+0

@Ragepotato:你是说数据绑定只适用于新实例分配给Sample属性,但如果Sample属性引用的现有实例的属性发生更改并通过INotifyPropertyChanged发信号通知它们,则不适用? – dthorpe 2011-06-15 21:20:41

+0

是的。该示例从未改变。它是同一个对象。它内的属性已更改。 你可以测试这个。在加载完所有内容后,将一个按钮放在控件上,Sample从虚拟机获取它的初始分配。然后将Sample指定给新的SampleType。记住它必须是正确的类型,否则绑定引擎会忽略它。如果你设置好双向绑定,你会看到你的转换被调用。 – Ragepotato 2011-06-16 05:56:14

回答

2

从这里几个类似的问题和几乎答案的提示,我有一个工作的解决方案,保留绑定。您可以手动强制绑定更新策略性放置事件中的源,如LostFocus:

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

XmlSource是绑定对象的父 数据的CLR读写属性 (未的DependencyProperty)。它是从XSD生成的.NET类型 。

我相信这是你的问题。基本的CLR属性不会通知,因此无法参与双向数据绑定。我的猜测是你会得到一次性绑定?您的输出窗口中是否有任何数据绑定错误?

您可以尝试创建包含XmlSource属性的类的包装,对该类执行INotifyPropertyChanged,并公开XmlSource作为通知特性(它需要是一个依赖属性)。

此外,关于此评论:

你是说的数据,如果一个新的实例分配给 样本属性绑定唯一 作品,但如果现有实例 的 性质的简称Sample属性更改为 ,并通过 INotifyPropertyChanged发出信号更改?

INotifyPropertyChanged的示例实现通常在属性本身发生更改时发生通知,而不是在子级或其他属性更改时发生。但是,您可以随时在任何属性上触发通知事件。例如,您可能拥有“全名”属性,只要“名字”或“姓氏”发生更改就会通知该属性。

如果以上内容没有帮助,我会建议发布一些更多的代码 - 也许是您尝试工作的简化版本。

编辑:

我想我误解你的问题。我认为问题就是你在评论中提到的 - 这是一个参考类型。可能是值得你OnSampleChanged尝试这样的:

private static void OnSampleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
{ 
    var oldValue = Sample; 
    Sample = new SampleType(); 
    Sample = oldValue; 
} 

我认为这将迫使结合系统识别的东西改变了目标端。

+0

XmlSource CLR属性已经实现了INotifyPropertyChanged。此外,转换器的ConvertBack将需要首先调用,以获得一个值来分配给XmlSource属性,并且不会调用ConvertBack。 – dthorpe 2011-06-16 17:45:10

0

有类似问题。解决方案如下:

而不是我使用一种方式和一个转换器的双向绑定。 转换器将对象(在您的情况下,xmlsource属性的父对象)转换(封装)到viewModel,然后控件绑定到它。

viewModel像代理一样工作,持有对对象的引用,管理它的属性,当然还实现INotifyPropertyChanged。 在这种情况下,您不需要调用ConvertBack方法,因为操作是通过viewModel在适当的实例上执行的。

让您拥有一个干净的看法,你不需要在xaml.cs任何代码