6

我设置了一个数据绑定,它使用转换器将笨拙的 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 方法?

4

3 回答 3

2

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

private void mycontrol_LostFocus(object sender, RoutedEventArgs e)
{
    if (mycontrol.IsModified)
    {
        var binding = mycontrol.GetBindingExpression(MyControl.SampleProperty);
        binding.UpdateSource();
    }
}
于 2011-07-08T19:42:46.007 回答
0

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

我没有使用两种方式绑定,而是使用一种方式和一个转换器。转换器将对象(在您的情况下为 xmlsource 属性的父对象)转换(封装)为 viewModel,并且控件绑定到它。

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

所以你有一个干净的视图,你不需要 xaml.cs 中的任何代码

于 2013-01-29T14:56:06.577 回答
0

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

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

您可以尝试创建一个包含 XmlSource 属性的类的包装器,使该类实现 INotifyPropertyChanged,并将 XmlSource 公开为通知属性(它不需要依赖项属性)。

此外,关于此评论:

您是说数据绑定仅在将新实例分配给 Sample 属性时才有效,而不是在 Sample 属性引用的现有实例的属性发生更改并通过 INotifyPropertyChanged 发出更改信号时才有效?

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

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

编辑:

我想我误解了你的问题。我认为问题在于您在评论中提到的问题-它是一种引用类型。可能值得在您的 OnSampleChanged 中尝试此操作:

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

我认为这将迫使绑定系统认识到目标端发生了一些变化。

于 2011-06-16T04:38:55.387 回答