web-dev-qa-db-ja.com

依存関係プロパティSetValue()とSetCurrentValue()の違いは何ですか

私がこれを求めている理由は、@ Greg D( この質問 から)によって代わりにSetCurrentValue()を使用するように勧められたためですが、ドキュメントを見てみましたが、表示されませんでした違いは何ですか。または、「バリューソースを変更せずに」とはどういう意味ですか?

SetValue()

依存関係プロパティ識別子で指定された、依存関係プロパティのローカル値を設定します。

SetCurrentValue()

値のソースを変更せずに、依存関係プロパティの値を設定します。

52
Jiew Meng

あなたが提供したMSDNリンクはそれを非常によく言っています:

このメソッドは、アプリケーションが宣言したプロパティの使用を無効にすることなく、独自のプロパティの1つの値をプログラムで設定するコンポーネントによって使用されます。 SetCurrentValueメソッドはプロパティの有効な値を変更しますが、既存のトリガー、データバインディング、およびスタイルは引き続き機能します。

TextBoxコントロールを作成していて、人々が次のようによく使用するTextプロパティを公開したとします。

<TextBox Text="{Binding SomeProperty}"/>

コントロールのコードで、SetValueを呼び出すと、上書き指定したものとのバインディングになります。ただし、SetCurrentValueを呼び出すと、プロパティが指定された値をとることが保証されますが、バインディングは破棄されません。

私の知る限り、グレッグのアドバイスは正しくありません。 CLRラッパープロパティからは常にGetValue/SetValueを使用する必要があります。 SetCurrentValueは、特定の値を取得するためにプロパティが必要であるが、プロパティに対して構成されているバインディング、トリガー、またはスタイルを上書きしたくないシナリオでより役立ちます。

55
Kent Boogaart

受け入れられた答えに加えて:

この投稿 がSetCurrentValue()を非常によく説明していることがわかりました。 Dependency Property Value Precedenceシステムが、バインドされた値を超えてローカル値を取得する方法に注意してください。これは、コメント投稿者の予期しない動作を説明しています。

2

デモハーネス(完全):

_class test : DependencyObject
{
    static DependencyProperty XyzProperty =
        DependencyProperty.Register("Xyz", typeof(int), typeof(test), new PropertyMetadata(42));

    public test()
    {
        /* ... see code shown below ... */
    }

    void inf()
    {
        var info = DependencyPropertyHelper.GetValueSource(this, XyzProperty);
        var msg = $@"{"//"
                   } {(int)GetValue(XyzProperty),2
                   } {(ReadLocalValue(XyzProperty) is int x ? "(Object)" + x : "UnsetValue"),12
                   } {info.BaseValueSource,9
                   } {(info.IsCurrent ? "" : "Not") + "Current",12
                   } {(info.IsCoerced ? "" : "Not") + "Coerced",12
                   }";
        Trace.WriteLine(msg);
    }
};
_

ディスカッションの例:

_                                      // v̲a̲l̲u̲e̲  s̲t̲o̲r̲e̲d̲-o̲b̲j̲      B̲V̲S̲    C̲u̲r̲r̲e̲n̲t̲?    C̲o̲e̲r̲c̲e̲d̲?
/*1*/                                    // 42  UnsetValue  Default  NotCurrent  NotCoerced

/*2*/ SetValue(XyzProperty, 5);          //  5   (Object)5    Local  NotCurrent  NotCoerced

/*3*/ SetValue(XyzProperty, 42);         // 42  (Object)42    Local  NotCurrent  NotCoerced

/*4*/ ClearValue(XyzProperty);           // 42  UnsetValue  Default  NotCurrent  NotCoerced

/*5*/ SetCurrentValue(XyzProperty, 5);   //  5   (Object)5  Default     Current     Coerced

/*6*/ SetCurrentValue(XyzProperty, 42);  // 42  UnsetValue  Default  NotCurrent  NotCoerced

/*7*/ SetValue(XyzProperty, 5);          //  5   (Object)5    Local  NotCurrent  NotCoerced
      SetCurrentValue(XyzProperty, 42);  // 42  (Object)42    Local     Current     Coerced
_

ディスカッション:

  1. DependencyPropertyが「42」である不在のDefaultValueの初期状態では、_BaseValueSource.Default_フラグがアサートされています。 ReadLocalValue()は、グローバルシングルトンインスタンス_DependencyProperty.UnsetValue_を返します。

  2. SetValue()は、期待どおりに_BaseValueSource.Local_値を内部的に格納します。

  3. SetValueを使用してDefaultValueと等しい値を格納しても、_BaseValueSource.Default_状態は復元されません(以下の#6と比較してください)。

  4. 代わりに、保存されている値またはバインディングの一部またはすべてを削除してDPを元の状態に復元する場合は、ClearValue()を呼び出します。 (下記の注を参照)

  5. SetCurrentValue()を使用すると、プロパティ値は強制によって生成され、_BaseValueSource.Local_モードはアサートされません。以前のBaseValueSourceDefaultは、プロパティが not であるにもかかわらず、実際にはDefaultValue

    重要:
    これは、GetValueSource()によって返されるBaseValueSourceが_BaseValueSource.Default_と等しいことを確認することは not aであることを意味します。優勢なプロパティ値がDPメタデータのデフォルト値であるかどうかの信頼できるインジケータ。

  6. 一方、上記の#3とは異なり、SetCurrentValue does DPメタデータのDefaultValueとの同等性をチェックして、値をプルーニングすると見なします。 「不要」としても冗長。この熱心なクリーンアップは、DPストレージの肥大化を緩和するように設計されている場合がありますが、完全に理解されていない場合にあいまいなバグにつながる可能性がある特殊なケースの「マスキング解除」動作により、DP状態の透過性も複雑になります。たとえば、#6は、DPをクリアしてClearValue() ..と区別できない元の状態に戻します。

  7. ...ただし、以前に保存されたBaseValueSourceCurrentであり、Localではない場合のみ; #5 /#6をペア#7と比較してください。ペア#7では、報告されたプロパティ値が同じであるにもかかわらず、内部状態フラグが大幅に異なります。

ClearValue()に関して

PropertyChangedCallbackが、プロパティの以前の値から最終的に変更されないSetValue()操作に対して呼び出されないことは明らかです。 SetValueは、進行中の変更が作業中のアクティブなプロパティの値に関連しているという暗黙の前提を持っているため、これは基本的なことです。直感的ではないのは、同じロジックがClearValue()にも適用されることです。

たとえば、#4では、ClearValueにより、ローカル値_42_が内部DPストレージから削除され、その他の内部状態の変更もすべて期待どおりに行われます。問題は、OnPropertyChangedが呼び出されるかどうか(または呼び出されないか)現在のClearValue呼び出し中には、前の値等しいメタデータのデフォルト値になりました。

「クリア」操作のセマンティクスは、以前の状態の要約破棄を意味するように見えるため(したがって、コンテキスト上任意であると見なされることが多い)、ClearValue()は、その前の状態にのみ依存します。特に、「変更」通知を起動するかどうかなど、new状態も関係する(および混ざり合う)重要な動作の場合。

0
Glenn Slayden