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メソッドが呼び出され、null以外のデータが返されますが、メソッドConvertBackが呼び出されることはありません。

SampleControlは、サンプルデータツリーとのUIインタラクションをカプセル化するUserControlです。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は、親データバインドオブジェクトの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 に答える
0

同様の問題がありました。解決策は次のとおりです。

双方向バインディングの代わりに、一方向とコンバーターを使用しました。コンバーターはオブジェクト(この場合はxmlsourceプロパティの親オブジェクト)をviewModelに変換(カプセル化)し、コントロールはそれにバインドします。

viewModelはプロキシのように機能し、オブジェクトへの参照を保持し、そのプロパティを管理し、もちろんINotifyPropertyChangedを実装します。この場合、操作はviewModelを介して適切なインスタンスで実行されるため、ConvertBackメソッドを呼び出す必要はありません。

したがって、ビューがきれいになり、xaml.csにコードは必要ありません。

于 2013-01-29T14:56:06.577 に答える