Bagikan melalui


Panggilan balik dan validasi properti dependensi (WPF .NET)

Artikel ini menjelaskan cara menentukan properti dependensi dan menerapkan panggilan balik properti dependensi. Panggilan balik mendukung validasi nilai, koersi nilai, dan logika lain yang diperlukan saat nilai properti berubah.

Penting

Dokumentasi Panduan Desktop untuk .NET 7 dan .NET 6 sedang dibangun.

Prasyarat

Artikel ini mengasumsikan pengetahuan dasar tentang properti dependensi, dan bahwa Anda telah membaca gambaran umum properti Dependensi. Untuk mengikuti contoh dalam artikel ini, ini membantu jika Anda terbiasa dengan Extensible Application Markup Language (XAML) dan tahu cara menulis aplikasi WPF.

Memvalidasi panggilan balik nilai

Panggilan balik nilai validasi menyediakan cara bagi Anda untuk memeriksa apakah nilai properti dependensi baru valid sebelum diterapkan oleh sistem properti. Panggilan balik ini menimbulkan pengecualian jika nilai tidak memenuhi kriteria validasi.

Panggilan balik nilai validasi hanya dapat ditetapkan ke properti dependensi sekali, selama pendaftaran properti. Saat mendaftarkan properti dependensi, Anda memiliki opsi untuk meneruskan ValidateValueCallback referensi ke Register(String, Type, Type, PropertyMetadata, ValidateValueCallback) metode . Panggilan balik nilai validasi bukan bagian dari metadata properti, dan tidak dapat ditimpa.

Nilai efektif properti dependensi adalah nilai yang diterapkan. Nilai efektif ditentukan melalui nilai properti yang diutamakan ketika ada beberapa input berbasis properti. Jika panggilan balik nilai validasi didaftarkan untuk properti dependensi, sistem properti akan memanggil panggilan balik nilai validasinya pada perubahan nilai, meneruskan nilai baru sebagai objek. Dalam panggilan balik, Anda dapat melemparkan kembali objek nilai ke jenis yang terdaftar dengan sistem properti, lalu menjalankan logika validasi Anda di atasnya. Panggilan balik mengembalikan true jika nilai valid untuk properti , jika tidak false.

Jika panggilan balik nilai validasi mengembalikan false, pengecualian dinaikkan dan nilai baru tidak diterapkan. Penulis aplikasi harus siap untuk menangani pengecualian ini. Penggunaan umum panggilan balik nilai validasi adalah memvalidasi nilai enumerasi, atau membatasi nilai numerik saat mewakili pengukuran yang memiliki batasan. Panggilan balik nilai validasi dipanggil oleh sistem properti dalam skenario yang berbeda, termasuk:

  • Inisialisasi objek, yang menerapkan nilai default pada waktu pembuatan.
  • Panggilan terprogram ke SetValue.
  • Penimpaan metadata yang menentukan nilai default baru.

Panggilan balik nilai validasi tidak memiliki parameter yang menentukan instans DependencyObject tempat nilai baru ditetapkan. Semua instans DependencyObject berbagi panggilan balik validasi-nilai yang sama, sehingga tidak dapat digunakan untuk memvalidasi skenario khusus instans. Untuk informasi selengkapnya, lihat ValidateValueCallback .

Contoh berikut menunjukkan cara mencegah properti, ditik sebagai Double, diatur ke PositiveInfinity atau NegativeInfinity.

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

Panggilan balik yang diubah properti

Panggilan balik yang diubah properti memberi tahu Anda ketika nilai efektif properti dependensi telah berubah.

Panggilan balik yang diubah properti adalah bagian dari metadata properti dependensi. Jika Anda berasal dari kelas yang menentukan properti dependensi, atau menambahkan kelas Anda sebagai pemilik properti dependensi, Anda dapat mengambil alih metadata. Saat mengambil alih metadata, Anda memiliki opsi untuk memberikan referensi baru PropertyChangedCallback . Gunakan panggilan balik yang diubah properti untuk menjalankan logika yang diperlukan saat nilai properti berubah.

Tidak seperti panggilan balik nilai validasi, panggilan balik yang diubah properti memiliki parameter yang menentukan instans DependencyObject tempat nilai baru diatur. Contoh berikutnya menunjukkan bagaimana panggilan balik yang diubah properti dapat menggunakan DependencyObject referensi instans untuk memicu panggilan balik nilai koerce.

Panggilan balik nilai koerce

Panggilan balik nilai koerce menyediakan cara bagi Anda untuk mendapatkan pemberitahuan ketika nilai efektif properti dependensi akan berubah, sehingga Anda dapat menyesuaikan nilai baru sebelum diterapkan. Selain dipicu oleh sistem properti, Anda dapat memanggil panggilan balik coerce-value dari kode Anda.

Panggilan balik nilai koersi adalah bagian dari metadata properti dependensi. Jika Anda berasal dari kelas yang menentukan properti dependensi, atau menambahkan kelas Anda sebagai pemilik properti dependensi, Anda dapat mengambil alih metadata. Saat mengambil alih metadata, Anda memiliki opsi untuk memberikan referensi ke baru CoerceValueCallback. Gunakan panggilan balik coerce-value untuk mengevaluasi nilai baru dan memaksanya jika diperlukan. Panggilan balik mengembalikan nilai yang dikoersi jika terjadi koersi, jika tidak, panggilan akan mengembalikan nilai baru yang tidak diubah.

Mirip dengan panggilan balik yang diubah properti, panggilan balik coerce-value memiliki parameter yang menentukan instans DependencyObject tempat nilai baru ditetapkan. Contoh berikutnya menunjukkan bagaimana panggilan balik nilai koersi dapat menggunakan DependencyObject referensi instans untuk memaksa nilai properti.

Catatan

Nilai properti default tidak dapat dipaksa. Properti dependensi memiliki nilai default yang diatur pada inisialisasi objek, atau saat Anda menghapus nilai lain menggunakan ClearValue.

Koerce-value dan callback yang diubah properti dalam kombinasi

Anda dapat membuat dependensi antara properti pada elemen, dengan menggunakan panggilan balik nilai koerce dan panggilan balik yang diubah properti dalam kombinasi. Misalnya, perubahan dalam satu pemaksaan paksa properti atau evaluasi ulang di properti dependensi lain. Contoh berikutnya menunjukkan skenario umum: tiga properti dependensi yang masing-masing menyimpan nilai saat ini, nilai minimum, dan nilai maksimum elemen UI. Jika nilai maksimum berubah sehingga kurang dari nilai saat ini, nilai saat ini kemudian diatur ke nilai maksimum baru. Dan, jika nilai minimum berubah sehingga lebih besar dari nilai saat ini, nilai saat ini kemudian diatur ke nilai minimum baru. Dalam contoh, PropertyChangedCallback untuk nilai saat ini secara eksplisit memanggil CoerceValueCallback untuk nilai minimum dan maksimum.

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

Skenario panggilan balik tingkat lanjut

Batasan dan nilai yang diinginkan

Jika nilai properti dependensi yang ditetapkan secara lokal diubah melalui koersi, nilai yang ditetapkan secara lokal yang tidak berubah dipertahankan sebagai nilai yang diinginkan. Jika koersi didasarkan pada nilai properti lain, sistem properti akan mengevaluasi kembali koersi secara dinamis setiap kali nilai lain berubah. Dalam batasan paksaan, sistem properti akan menerapkan nilai yang paling dekat dengan nilai yang diinginkan. Jika kondisi koersi tidak lagi berlaku, sistem properti akan memulihkan nilai yang diinginkan—dengan asumsi tidak ada nilai prioritas yang lebih tinggi yang aktif. Contoh berikut menguji koersi dalam nilai saat ini, nilai minimum, dan skenario nilai maksimum.

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

Skenario dependensi yang cukup kompleks dapat terjadi ketika Anda memiliki beberapa properti yang bergantung satu sama lain secara melingkar. Secara teknis, tidak ada yang salah dengan dependensi kompleks—kecuali bahwa sejumlah besar evaluasi ulang dapat mengurangi performa. Selain itu, dependensi kompleks yang terekspos di UI mungkin membingungkan pengguna. Perlakukan PropertyChangedCallback dan CoerceValueCallback sebigu mungkin, dan jangan terlalu membatasi.

Batalkan perubahan nilai

Dengan mengembalikan UnsetValue dari CoerceValueCallback, Anda dapat menolak perubahan nilai properti. Mekanisme ini berguna ketika perubahan nilai properti dimulai secara asinkron, tetapi ketika diterapkan tidak lagi valid untuk status objek saat ini. Skenario lain mungkin untuk secara selektif menekan perubahan nilai berdasarkan asalnya. Dalam contoh berikut, CoerceValueCallback memanggil GetValueSource metode , yang mengembalikan ValueSource struktur dengan BaseValueSource enumerasi yang mengidentifikasi sumber nilai baru.

// 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

Baca juga