Aracılığıyla paylaş


Bağımlılık özelliği geri çağırmaları ve doğrulama (WPF .NET)

Bu makalede bağımlılık özelliğini tanımlama ve bağımlılık özelliği geri çağırmalarını uygulama açıklanmaktadır. Geri çağırmalar değer doğrulamayı, değer zorlamasını ve özellik değeri değiştiğinde gereken diğer mantığı destekler.

Önkoşullar

Makalede bağımlılık özellikleri hakkında temel bilgiler edindiğiniz ve Bağımlılık özelliklerine genel bakış makalesini okuduğunuz varsayılır. Bu makaledeki örnekleri takip etmek için Genişletilebilir Uygulama biçimlendirme dili (XAML) hakkında bilgi sahibi olmanız ve WPF uygulamalarının nasıl yazabileceğinizi bilmeniz yardımcı olur.

Doğrulama-değer geri çağırmaları

Validate-value geri çağırmaları, yeni bağımlılık özellik değerinin özellik sistemi tarafından uygulanmadan önce geçerli olup olmadığını denetlemeniz için bir yol sağlar. Bu geri çağırma, değer doğrulama ölçütlerini karşılamıyorsa bir özel durum oluşturur.

Validate-value geri çağırmaları, özellik kaydı sırasında bağımlılık özelliğine yalnızca bir kez atanabilir. Bağımlılık özelliğini kaydederken yöntemine bir ValidateValueCallback başvuru Register(String, Type, Type, PropertyMetadata, ValidateValueCallback) geçirme seçeneğiniz vardır. Validate-value geri çağırmaları özellik meta verilerinin bir parçası değildir ve geçersiz kılınamaz.

Bağımlılık özelliğinin geçerli değeri, uygulanan değeridir. Etkin değer, birden çok özellik tabanlı giriş mevcut olduğunda özellik değeri önceliği üzerinden belirlenir. Bir bağımlılık özelliği için validate-value geri çağırması kaydedilirse, özellik sistemi yeni değeri nesne olarak geçirerek değer değişikliğinde validate-value geri çağırmasını çağırır. Geri çağırma içinde, değer nesnesini özellik sistemiyle kaydedilen türe geri döndürebilir ve ardından doğrulama mantığınızı üzerinde çalıştırabilirsiniz. Geri çağırma, değer özelliği için geçerliyse döndürür true , aksi takdirde false.

Bir validate-value geri çağırma döndürürse false, bir özel durum oluşturulur ve yeni değer uygulanmaz. Uygulama yazarları bu özel durumları işlemeye hazır olmalıdır. Validate-value geri çağırmalarının yaygın bir kullanımı, numaralandırma değerlerini doğrulamak veya sınırları olan ölçümleri temsil eden sayısal değerleri kısıtlamaktır. Validate-value geri çağırmaları, aşağıdakiler gibi farklı senaryolarda özellik sistemi tarafından çağrılır:

  • Oluşturma zamanında varsayılan bir değer uygulayan nesne başlatma.
  • için programlı çağrılar SetValue.
  • Yeni bir varsayılan değer belirten meta veri geçersiz kılmaları.

Validate-value geri çağırmaları, yeni değerin DependencyObject ayarlandığı örneği belirten bir parametreye sahip değildir. Bir DependencyObject örneğin tüm örnekleri aynı validate-value geri çağırmasını paylaştığından örneğe özgü senaryoları doğrulamak için kullanılamaz. Daha fazla bilgi için bkz. ValidateValueCallback.

Aşağıdaki örnekte, olarak yazılan bir özelliğin veya NegativeInfinityolarak Doubleayarlanmasının PositiveInfinity nasıl önlendiği gösterilmektedir.

public class Gauge1 : Control
{
    public Gauge1() : base() { }

    // Register a dependency property with the specified property name,
    // property type, owner type, property metadata, and callbacks.
    public static readonly DependencyProperty CurrentReadingProperty =
        DependencyProperty.Register(
            name: "CurrentReading",
            propertyType: typeof(double),
            ownerType: typeof(Gauge1),
            typeMetadata: new FrameworkPropertyMetadata(
                defaultValue: double.NaN,
                flags: FrameworkPropertyMetadataOptions.AffectsMeasure),
            validateValueCallback: new ValidateValueCallback(IsValidReading));

    // CLR wrapper with get/set accessors.
    public double CurrentReading
    {
        get => (double)GetValue(CurrentReadingProperty);
        set => SetValue(CurrentReadingProperty, value);
    }

    // Validate-value callback.
    public static bool IsValidReading(object value)
    {
        double val = (double)value;
        return !val.Equals(double.NegativeInfinity) && 
            !val.Equals(double.PositiveInfinity);
    }
}
Public Class Gauge1
    Inherits Control

    Public Sub New()
        MyBase.New()
    End Sub

    Public Shared ReadOnly CurrentReadingProperty As DependencyProperty =
        DependencyProperty.Register(
            name:="CurrentReading",
            propertyType:=GetType(Double),
            ownerType:=GetType(Gauge1),
            typeMetadata:=New FrameworkPropertyMetadata(
                defaultValue:=Double.NaN,
                flags:=FrameworkPropertyMetadataOptions.AffectsMeasure),
            validateValueCallback:=New ValidateValueCallback(AddressOf IsValidReading))

    Public Property CurrentReading As Double
        Get
            Return GetValue(CurrentReadingProperty)
        End Get
        Set(value As Double)
            SetValue(CurrentReadingProperty, value)
        End Set
    End Property

    Public Shared Function IsValidReading(value As Object) As Boolean
        Dim val As Double = value
        Return Not val.Equals(Double.NegativeInfinity) AndAlso
            Not val.Equals(Double.PositiveInfinity)
    End Function

End Class
public static void TestValidationBehavior()
{
    Gauge1 gauge = new();

    Debug.WriteLine($"Test value validation scenario:");

    // Set allowed value.
    gauge.CurrentReading = 5;
    Debug.WriteLine($"Current reading: {gauge.CurrentReading}");

    try
    {
        // Set disallowed value.
        gauge.CurrentReading = double.PositiveInfinity;
    }
    catch (ArgumentException e)
    {
        Debug.WriteLine($"Exception thrown by ValidateValueCallback: {e.Message}");
    }

    Debug.WriteLine($"Current reading: {gauge.CurrentReading}");

    // Current reading: 5
    // Exception thrown by ValidateValueCallback: '∞' is not a valid value for property 'CurrentReading'.
    // Current reading: 5
}
Public Shared Sub TestValidationBehavior()
    Dim gauge As New Gauge1()

    Debug.WriteLine($"Test value validation scenario:")

    ' Set allowed value.
    gauge.CurrentReading = 5
    Debug.WriteLine($"Current reading: {gauge.CurrentReading}")

    Try
        ' Set disallowed value.
        gauge.CurrentReading = Double.PositiveInfinity
    Catch e As ArgumentException
        Debug.WriteLine($"Exception thrown by ValidateValueCallback: {e.Message}")
    End Try

    Debug.WriteLine($"Current reading: {gauge.CurrentReading}")

    ' Current reading: 5
    ' Exception thrown by ValidateValueCallback: '∞' is not a valid value for property 'CurrentReading'.
    ' Current reading 5
End Sub

Özellik tarafından değiştirilen geri çağırmalar

Özellik değiştirme geri çağırmaları, bağımlılık özelliğinin etkin değeri değiştiğinde sizi bilgilendirir.

Özellik değiştirilen geri çağırmalar bağımlılık özelliği meta verilerinin bir parçasıdır. Bağımlılık özelliğini tanımlayan bir sınıftan türetilirseniz veya sınıfınızı bağımlılık özelliğinin sahibi olarak eklerseniz, meta verileri geçersiz kılabilirsiniz. Meta verileri geçersiz kıldığınızda, yeni PropertyChangedCallback bir başvuru sağlama seçeneğiniz vardır. Özellik değeri değiştiğinde gereken mantığı çalıştırmak için özellik tarafından değiştirilen bir geri çağırma kullanın.

Validate-value geri çağırmalarından farklı olarak, özellik tarafından değiştirilen geri çağırmalar, yeni değerin DependencyObject ayarlandığı örneği belirten bir parametreye sahiptir. Sonraki örnekte, özellik tarafından değiştirilen bir geri çağırmanın DependencyObject zorlama-değer geri çağırmalarını tetikleme amacıyla örnek başvuruyu nasıl kullanabileceği gösterilmektedir.

Coerce-value geri çağırmaları

Coerce-value geri çağırmaları, bağımlılık özelliğinin etkin değeri değişmek üzereyken size bildirim almanız için bir yol sağlar, böylece yeni değeri uygulanmadan önce ayarlayabilirsiniz. Özellik sistemi tarafından tetiklenmenin yanı sıra, kodunuzdan coerce-value geri çağırmaları da çağırabilirsiniz.

Coerce-value geri çağırmaları bağımlılık özelliği meta verilerinin bir parçasıdır. Bağımlılık özelliğini tanımlayan bir sınıftan türetilirseniz veya sınıfınızı bağımlılık özelliğinin sahibi olarak eklerseniz, meta verileri geçersiz kılabilirsiniz. Meta verileri geçersiz kıldığınızda, yeni CoerceValueCallbackbir öğesine başvuru sağlama seçeneğiniz vardır. Yeni değerleri değerlendirmek ve gerektiğinde zorlamak için bir zorlama-değer geri çağırması kullanın. Geri çağırma, zorlama oluşursa zorlanmış değeri döndürür, aksi takdirde değişmemiş yeni değeri döndürür.

Özellik tarafından değiştirilen geri çağırmalara benzer şekilde, coerce-value geri çağırmaları da yeni değerin DependencyObject ayarlandığı örneği belirten bir parametreye sahiptir. Sonraki örnekte, bir coerce-value geri çağırmasının özellik değerlerini zorlamak için örnek başvurularını nasıl kullanabileceği DependencyObject gösterilir.

Not

Varsayılan özellik değerleri zorunlu olamaz. Bağımlılık özelliğinin varsayılan değeri nesne başlatmada veya kullanarak ClearValuediğer değerleri temizlediğinizde ayarlanmıştır.

Coerce-value ve özellik tarafından değiştirilen geri çağırmalar birlikte

Coerce-value geri çağırmalarını ve özellik tarafından değiştirilen geri çağırmaları birlikte kullanarak bir öğedeki özellikler arasında bağımlılıklar oluşturabilirsiniz. Örneğin, bir özellikteki değişiklikler başka bir bağımlılık özelliğinde zorlamayı veya yeniden değerlendirmeyi zorlar. Sonraki örnekte yaygın bir senaryo gösterilmektedir: sırasıyla geçerli değeri, en düşük değeri ve kullanıcı arabirimi öğesinin en yüksek değerini depolayan üç bağımlılık özelliği. En büyük değer geçerli değerden küçük olacak şekilde değişirse, geçerli değer yeni en büyük değere ayarlanır. En düşük değer geçerli değerden büyük olacak şekilde değişirse, geçerli değer yeni minimum değere ayarlanır. Örnekte, PropertyChangedCallback geçerli değer için değeri, en düşük ve en yüksek değerler için açıkça öğesini CoerceValueCallback çağırır.

public class Gauge2 : Control
{
    public Gauge2() : base() { }

    // Register a dependency property with the specified property name,
    // property type, owner type, property metadata, and callbacks.
    public static readonly DependencyProperty CurrentReadingProperty =
        DependencyProperty.Register(
            name: "CurrentReading",
            propertyType: typeof(double),
            ownerType: typeof(Gauge2),
            typeMetadata: new FrameworkPropertyMetadata(
                defaultValue: double.NaN,
                flags: FrameworkPropertyMetadataOptions.AffectsMeasure,
                propertyChangedCallback: new PropertyChangedCallback(OnCurrentReadingChanged),
                coerceValueCallback: new CoerceValueCallback(CoerceCurrentReading)
            ),
            validateValueCallback: new ValidateValueCallback(IsValidReading)
        );

    // CLR wrapper with get/set accessors.
    public double CurrentReading
    {
        get => (double)GetValue(CurrentReadingProperty);
        set => SetValue(CurrentReadingProperty, value);
    }

    // Validate-value callback.
    public static bool IsValidReading(object value)
    {
        double val = (double)value;
        return !val.Equals(double.NegativeInfinity) && !val.Equals(double.PositiveInfinity);
    }

    // Property-changed callback.
    private static void OnCurrentReadingChanged(DependencyObject depObj, DependencyPropertyChangedEventArgs e)
    {
        depObj.CoerceValue(MinReadingProperty);
        depObj.CoerceValue(MaxReadingProperty);
    }

    // Coerce-value callback.
    private static object CoerceCurrentReading(DependencyObject depObj, object value)
    {
        Gauge2 gauge = (Gauge2)depObj;
        double currentVal = (double)value;
        currentVal = currentVal < gauge.MinReading ? gauge.MinReading : currentVal;
        currentVal = currentVal > gauge.MaxReading ? gauge.MaxReading : currentVal;
        return currentVal;
    }

    // Register a dependency property with the specified property name,
    // property type, owner type, property metadata, and callbacks.
    public static readonly DependencyProperty MaxReadingProperty = DependencyProperty.Register(
        name: "MaxReading",
        propertyType: typeof(double),
        ownerType: typeof(Gauge2),
        typeMetadata: new FrameworkPropertyMetadata(
            defaultValue: double.NaN,
            flags: FrameworkPropertyMetadataOptions.AffectsMeasure,
            propertyChangedCallback: new PropertyChangedCallback(OnMaxReadingChanged),
            coerceValueCallback: new CoerceValueCallback(CoerceMaxReading)
        ),
        validateValueCallback: new ValidateValueCallback(IsValidReading)
    );

    // CLR wrapper with get/set accessors.
    public double MaxReading
    {
        get => (double)GetValue(MaxReadingProperty);
        set => SetValue(MaxReadingProperty, value);
    }

    // Property-changed callback.
    private static void OnMaxReadingChanged(DependencyObject depObj, DependencyPropertyChangedEventArgs e)
    {
        depObj.CoerceValue(MinReadingProperty);
        depObj.CoerceValue(CurrentReadingProperty);
    }

    // Coerce-value callback.
    private static object CoerceMaxReading(DependencyObject depObj, object value)
    {
        Gauge2 gauge = (Gauge2)depObj;
        double maxVal = (double)value;
        return maxVal < gauge.MinReading ? gauge.MinReading : maxVal;
    }

    // Register a dependency property with the specified property name,
    // property type, owner type, property metadata, and callbacks.
    public static readonly DependencyProperty MinReadingProperty = DependencyProperty.Register(
    name: "MinReading",
    propertyType: typeof(double),
    ownerType: typeof(Gauge2),
    typeMetadata: new FrameworkPropertyMetadata(
        defaultValue: double.NaN,
        flags: FrameworkPropertyMetadataOptions.AffectsMeasure,
        propertyChangedCallback: new PropertyChangedCallback(OnMinReadingChanged),
        coerceValueCallback: new CoerceValueCallback(CoerceMinReading)
    ),
    validateValueCallback: new ValidateValueCallback(IsValidReading));

    // CLR wrapper with get/set accessors.
    public double MinReading
    {
        get => (double)GetValue(MinReadingProperty);
        set => SetValue(MinReadingProperty, value);
    }

    // Property-changed callback.
    private static void OnMinReadingChanged(DependencyObject depObj, DependencyPropertyChangedEventArgs e)
    {
        depObj.CoerceValue(MaxReadingProperty);
        depObj.CoerceValue(CurrentReadingProperty);
    }

    // Coerce-value callback.
    private static object CoerceMinReading(DependencyObject depObj, object value)
    {
        Gauge2 gauge = (Gauge2)depObj;
        double minVal = (double)value;
        return minVal > gauge.MaxReading ? gauge.MaxReading : minVal;
    }
}
Public Class Gauge2
    Inherits Control

    Public Sub New()
        MyBase.New()
    End Sub

    ' Register a dependency property with the specified property name,
    ' property type, owner type, property metadata, And callbacks.
    Public Shared ReadOnly CurrentReadingProperty As DependencyProperty =
        DependencyProperty.Register(
            name:="CurrentReading",
            propertyType:=GetType(Double),
            ownerType:=GetType(Gauge2),
            typeMetadata:=New FrameworkPropertyMetadata(
                defaultValue:=Double.NaN,
                flags:=FrameworkPropertyMetadataOptions.AffectsMeasure,
                propertyChangedCallback:=New PropertyChangedCallback(AddressOf OnCurrentReadingChanged),
                coerceValueCallback:=New CoerceValueCallback(AddressOf CoerceCurrentReading)),
            validateValueCallback:=New ValidateValueCallback(AddressOf IsValidReading))

    ' CLR wrapper with get/set accessors.
    Public Property CurrentReading As Double
        Get
            Return GetValue(CurrentReadingProperty)
        End Get
        Set(value As Double)
            SetValue(CurrentReadingProperty, value)
        End Set
    End Property

    ' Validate-value callback.
    Public Shared Function IsValidReading(value As Object) As Boolean
        Dim val As Double = value
        Return Not val.Equals(Double.NegativeInfinity) AndAlso Not val.Equals(Double.PositiveInfinity)
    End Function

    ' Property-changed callback.
    Private Shared Sub OnCurrentReadingChanged(depObj As DependencyObject, e As DependencyPropertyChangedEventArgs)
        depObj.CoerceValue(MinReadingProperty)
        depObj.CoerceValue(MaxReadingProperty)
    End Sub

    ' Coerce-value callback.
    Private Shared Function CoerceCurrentReading(depObj As DependencyObject, value As Object) As Object
        Dim gauge As Gauge2 = CType(depObj, Gauge2)
        Dim currentVal As Double = value
        currentVal = If(currentVal < gauge.MinReading, gauge.MinReading, currentVal)
        currentVal = If(currentVal > gauge.MaxReading, gauge.MaxReading, currentVal)
        Return currentVal
    End Function

    Public Shared ReadOnly MaxReadingProperty As DependencyProperty =
        DependencyProperty.Register(
        name:="MaxReading",
        propertyType:=GetType(Double),
        ownerType:=GetType(Gauge2),
        typeMetadata:=New FrameworkPropertyMetadata(
            defaultValue:=Double.NaN,
            flags:=FrameworkPropertyMetadataOptions.AffectsMeasure,
            propertyChangedCallback:=New PropertyChangedCallback(AddressOf OnMaxReadingChanged),
            coerceValueCallback:=New CoerceValueCallback(AddressOf CoerceMaxReading)),
        validateValueCallback:=New ValidateValueCallback(AddressOf IsValidReading))

    ' CLR wrapper with get/set accessors.
    Public Property MaxReading As Double
        Get
            Return GetValue(MaxReadingProperty)
        End Get
        Set(value As Double)
            SetValue(MaxReadingProperty, value)
        End Set
    End Property

    ' Property-changed callback.
    Private Shared Sub OnMaxReadingChanged(depObj As DependencyObject, e As DependencyPropertyChangedEventArgs)
        depObj.CoerceValue(MinReadingProperty)
        depObj.CoerceValue(CurrentReadingProperty)
    End Sub

    ' Coerce-value callback.
    Private Shared Function CoerceMaxReading(depObj As DependencyObject, value As Object) As Object
        Dim gauge As Gauge2 = CType(depObj, Gauge2)
        Dim maxVal As Double = value
        Return If(maxVal < gauge.MinReading, gauge.MinReading, maxVal)
    End Function

    ' Register a dependency property with the specified property name,
    ' property type, owner type, property metadata, And callbacks.
    Public Shared ReadOnly MinReadingProperty As DependencyProperty =
        DependencyProperty.Register(
        name:="MinReading",
        propertyType:=GetType(Double),
        ownerType:=GetType(Gauge2),
        typeMetadata:=New FrameworkPropertyMetadata(
            defaultValue:=Double.NaN,
            flags:=FrameworkPropertyMetadataOptions.AffectsMeasure,
            propertyChangedCallback:=New PropertyChangedCallback(AddressOf OnMinReadingChanged),
            coerceValueCallback:=New CoerceValueCallback(AddressOf CoerceMinReading)),
        validateValueCallback:=New ValidateValueCallback(AddressOf IsValidReading))

    ' CLR wrapper with get/set accessors.
    Public Property MinReading As Double
        Get
            Return GetValue(MinReadingProperty)
        End Get
        Set(value As Double)
            SetValue(MinReadingProperty, value)
        End Set
    End Property

    ' Property-changed callback.
    Private Shared Sub OnMinReadingChanged(depObj As DependencyObject, e As DependencyPropertyChangedEventArgs)
        depObj.CoerceValue(MaxReadingProperty)
        depObj.CoerceValue(CurrentReadingProperty)
    End Sub

    ' Coerce-value callback.
    Private Shared Function CoerceMinReading(depObj As DependencyObject, value As Object) As Object
        Dim gauge As Gauge2 = CType(depObj, Gauge2)
        Dim minVal As Double = value
        Return If(minVal > gauge.MaxReading, gauge.MaxReading, minVal)
    End Function

End Class

Gelişmiş geri çağırma senaryoları

Kısıtlamalar ve istenen değerler

Bir bağımlılık özelliğinin yerel olarak ayarlanan değeri zorlama yoluyla değiştirilirse, değişmemiş yerel olarak ayarlanan değer istenen değer olarak korunur. Zorlama diğer özellik değerlerini temel alırsa, diğer değerler değiştiğinde özellik sistemi zorlamayı dinamik olarak yeniden değerlendirir. Zorlama kısıtlamaları içinde, özellik sistemi istenen değere en yakın değeri uygular. Zorlama koşulu artık geçerli değilse, özellik sistemi daha yüksek bir öncelik değerinin etkin olmadığı varsayılarak istenen değeri geri yükler. Aşağıdaki örnek geçerli değer, en düşük değer ve en yüksek değer senaryosundaki zorlamayı test ediyor.

public static void TestCoercionBehavior()
{
    Gauge2 gauge = new()
    {
        // Set initial values.
        MinReading = 0,
        MaxReading = 10,
        CurrentReading = 5
    };

    Debug.WriteLine($"Test current/min/max values scenario:");

    // Current reading is not coerced.
    Debug.WriteLine($"Current reading: " +
        $"{gauge.CurrentReading} (min: {gauge.MinReading}, max: {gauge.MaxReading})");

    // Current reading is coerced to max value.
    gauge.MaxReading = 3;
    Debug.WriteLine($"Current reading: " +
        $"{gauge.CurrentReading} (min: {gauge.MinReading}, max: {gauge.MaxReading})");

    // Current reading is coerced, but tracking back to the desired value.
    gauge.MaxReading = 4;
    Debug.WriteLine($"Current reading: " +
        $"{gauge.CurrentReading} (min: {gauge.MinReading}, max: {gauge.MaxReading})");

    // Current reading reverts to the desired value.
    gauge.MaxReading = 10;
    Debug.WriteLine($"Current reading: " +
        $"{gauge.CurrentReading} (min: {gauge.MinReading}, max: {gauge.MaxReading})");

    // Current reading remains at the desired value.
    gauge.MinReading = 5;
    gauge.MaxReading = 5;
    Debug.WriteLine($"Current reading: " +
        $"{gauge.CurrentReading} (min: {gauge.MinReading}, max: {gauge.MaxReading})");

    // Current reading: 5 (min=0, max=10)
    // Current reading: 3 (min=0, max=3)
    // Current reading: 4 (min=0, max=4)
    // Current reading: 5 (min=0, max=10)
    // Current reading: 5 (min=5, max=5)
}
Public Shared Sub TestCoercionBehavior()

    ' Set initial values.
    Dim gauge As New Gauge2 With {
        .MinReading = 0,
        .MaxReading = 10,
        .CurrentReading = 5
    }

    Debug.WriteLine($"Test current/min/max values scenario:")

    ' Current reading is not coerced.
    Debug.WriteLine($"Current reading: " &
        $"{gauge.CurrentReading} (min={gauge.MinReading}, max={gauge.MaxReading})")

    ' Current reading is coerced to max value.
    gauge.MaxReading = 3
    Debug.WriteLine($"Current reading: " &
        $"{gauge.CurrentReading} (min={gauge.MinReading}, max={gauge.MaxReading})")

    ' Current reading is coerced, but tracking back to the desired value.
    gauge.MaxReading = 4
    Debug.WriteLine($"Current reading: " &
        $"{gauge.CurrentReading} (min={gauge.MinReading}, max={gauge.MaxReading})")

    ' Current reading reverts to the desired value.
    gauge.MaxReading = 10
    Debug.WriteLine($"Current reading: " &
        $"{gauge.CurrentReading} (min={gauge.MinReading}, max={gauge.MaxReading})")

    ' Current reading remains at the desired value.
    gauge.MinReading = 5
    gauge.MaxReading = 5
    Debug.WriteLine($"Current reading: " &
        $"{gauge.CurrentReading} (min={gauge.MinReading}, max={gauge.MaxReading})")

    ' Current reading: 5 (min=0, max=10)
    ' Current reading: 3 (min=0, max=3)
    ' Current reading: 4 (min=0, max=4)
    ' Current reading: 5 (min=0, max=10)
    ' Current reading: 5 (min=5, max=5)
End Sub

Döngüsel bir şekilde birbirine bağımlı birden çok özelliğiniz olduğunda oldukça karmaşık bağımlılık senaryoları oluşabilir. Teknik olarak, çok sayıda yeniden değerlendirmenin performansı düşürebileceği dışında karmaşık bağımlılıklarda bir sorun yoktur. Ayrıca, kullanıcı arabiriminde kullanıma sunulan karmaşık bağımlılıklar kullanıcıların kafasını karıştırabilir. PropertyChangedCallback mümkün CoerceValueCallback olduğunca belirsiz davranın ve aşırı kısıtlama yapmayın.

Değer değişikliklerini iptal etme

bir CoerceValueCallback'den döndürerek UnsetValue bir özellik değeri değişikliğini reddedebilirsiniz. Bu mekanizma, bir özellik değeri değişikliği zaman uyumsuz olarak başlatıldığında, ancak uygulandığında geçerli nesne durumu için artık geçerli olmadığında kullanışlıdır. Başka bir senaryo, bir değer değişikliğinin kaynağını temel alarak seçmeli olarak gizlenmek olabilir. Aşağıdaki örnekte, yeni değerin CoerceValueCallback GetValueSource kaynağını tanımlayan bir numaralandırmaya sahip bir ValueSource BaseValueSource yapı döndüren yöntemini çağırır.

// Coerce-value callback.
private static object CoerceCurrentReading(DependencyObject depObj, object value)
{
    // Get value source.
    ValueSource valueSource = 
        DependencyPropertyHelper.GetValueSource(depObj, CurrentReadingProperty);

    // Reject any property value change that's a locally set value.
    return valueSource.BaseValueSource == BaseValueSource.Local ? 
        DependencyProperty.UnsetValue : value;
}
' Coerce-value callback.
Private Shared Function CoerceCurrentReading(depObj As DependencyObject, value As Object) As Object
    ' Get value source.
    Dim valueSource As ValueSource =
        DependencyPropertyHelper.GetValueSource(depObj, CurrentReadingProperty)

    ' Reject any property value that's a locally set value.
    Return If(valueSource.BaseValueSource = BaseValueSource.Local, DependencyProperty.UnsetValue, value)
End Function

Ayrıca bkz.