Partager via


Rappels et validation des propriétés de dépendance (WPF .NET)

Cet article explique comment définir une propriété de dépendance et implémenter des rappels de propriété de dépendance. Les rappels prennent en charge la validation de valeur, la contrainte de valeur et d’autres logiques nécessaires lorsqu’une valeur de propriété change.

Conditions préalables

L’article suppose une connaissance de base des propriétés de dépendance et que vous avez lu vue d’ensemble des propriétés de dépendance. Pour suivre les exemples de cet article, il vous aide à connaître le langage XAML (Extensible Application Markup Language) et à savoir comment écrire des applications WPF.

Fonctions de rappel pour la validation des valeurs

Les rappels validate-value permettent de vérifier si une nouvelle valeur de propriété de dépendance est valide avant d’être appliquée par le système de propriétés. Ce rappel déclenche une exception si la valeur ne répond pas aux critères de validation.

Les rappels de validation de valeur ne peuvent être attribués qu'à une propriété de dépendance une seule fois, lors de l'enregistrement de la propriété. Lors de l’inscription d’une propriété de dépendance, vous avez la possibilité de transmettre une référence ValidateValueCallback à la méthode Register(String, Type, Type, PropertyMetadata, ValidateValueCallback). Les rappels validate-valeur ne font pas partie des métadonnées de propriété et ne peuvent pas être substitués.

La valeur effective d’une propriété de dépendance est sa valeur appliquée. La valeur effective est déterminée par priorité de valeur de propriété lorsque plusieurs entrées basées sur des propriétés existent. Si un rappel de valeur de validation est inscrit pour une propriété de dépendance, le système de propriétés appelle son rappel de valeur de validation lors de la modification de la valeur, en passant la nouvelle valeur en tant qu’objet. Dans le rappel, vous pouvez convertir l’objet valeur au type inscrit dans le système de propriétés, puis appliquer votre logique de validation sur celui-ci. Le rappel retourne true si la valeur est valide pour la propriété, sinon false.

Si un rappel de validation de valeur retourne false, une exception est levée et la nouvelle valeur n’est pas appliquée. Les développeurs d'applications doivent être prêts à traiter ces exceptions. Une utilisation courante des rappels validate-valeur consiste à valider des valeurs d’énumération ou à limiter les valeurs numériques lorsqu’elles représentent des mesures qui ont des limites. Les rappels de validation de valeur sont appelés par le système de propriétés dans différents scénarios, notamment :

  • Initialisation d’objet, qui applique une valeur par défaut au moment de la création.
  • Appels programmatiques à SetValue.
  • Les remplacements de métadonnées qui spécifient une nouvelle valeur par défaut.

Les rappels validate-valeur n’ont pas de paramètre qui spécifie l’instance de DependencyObject sur laquelle la nouvelle valeur est définie. Toutes les instances d’un DependencyObject partagent le même rappel de valeur de validation. Il ne peut donc pas être utilisé pour valider des scénarios spécifiques à l’instance. Pour plus d’informations, consultez ValidateValueCallback.

L’exemple suivant montre comment empêcher une propriété, dont le type est Double, de prendre la valeur PositiveInfinity ou 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

Rappels sur changement de propriété

Les rappels de changement de propriété vous informent lorsque la valeur effective d’une propriété dépendante a changé.

Les rappels de changement de propriété font partie des métadonnées des propriétés dépendantes. Si vous dérivez d’une classe qui définit une propriété de dépendance ou ajoutez votre classe en tant que propriétaire d’une propriété de dépendance, vous pouvez remplacer les métadonnées. En cas de substitution de métadonnées, vous avez la possibilité de fournir une nouvelle référence PropertyChangedCallback. Utilisez un rappel modifié par propriété pour exécuter une logique nécessaire lorsqu’une valeur de propriété change.

Contrairement aux rappels validate-value, les rappels modifiés par les propriétés ont un paramètre qui spécifie l’instance DependencyObject sur laquelle la nouvelle valeur est définie. L’exemple suivant montre comment un rappel de changement de propriété peut utiliser la référence d’instance DependencyObject pour déclencher des rappels de coercition de valeur.

Rappels de valeur de force

Les rappels de valeur coerce vous permettent d’être averti lorsque la valeur effective d’une propriété de dépendance est sur le point de changer, afin que vous puissiez ajuster la nouvelle valeur avant son application. En plus d’être déclenché par le système de propriétés, vous pouvez appeler des rappels de valeur de force à partir de votre code.

Les rappels de valeur de coerce font partie des métadonnées de propriété de dépendance. Si vous dérivez d’une classe qui définit une propriété de dépendance ou ajoutez votre classe en tant que propriétaire d’une propriété de dépendance, vous pouvez remplacer les métadonnées. En cas de substitution des métadonnées, vous avez la possibilité de fournir une référence à une nouvelle CoerceValueCallback. Utilisez un rappel de valeur de force pour évaluer de nouvelles valeurs et les forcer si nécessaire. La fonction de rappel retourne la valeur contrainte si une contrainte s'est produite ; sinon, elle retourne la nouvelle valeur inchangée.

Comme pour les rappels modifiés par les propriétés, les rappels de valeur de contrainte ont un paramètre qui spécifie l’instance de DependencyObject sur laquelle la nouvelle valeur est définie. L’exemple suivant montre comment un rappel de coercition de valeur peut utiliser une référence d’instance DependencyObject afin de contraindre les valeurs des propriétés.

Note

Les valeurs de propriété par défaut ne peuvent pas être coédées. Une propriété de dépendance a sa valeur par défaut définie sur l’initialisation d’objet ou lorsque vous effacez d’autres valeurs à l’aide de ClearValue.

Rappels de conversion de valeur et de changement de propriété combinés

Vous pouvez créer des dépendances entre les propriétés d’un élément à l’aide de rappels de contrainte de valeur et de rappels de changement de propriété en combinaison. Par exemple, les modifications apportées à une propriété entraînent une coercition ou une réévaluation dans une autre propriété de dépendance. L’exemple suivant montre un scénario courant : trois propriétés de dépendance qui stockent respectivement la valeur actuelle, la valeur minimale et la valeur maximale d’un élément d’interface utilisateur. Si la valeur maximale change afin qu’elle soit inférieure à la valeur actuelle, la valeur actuelle est alors définie sur la nouvelle valeur maximale. Et, si la valeur minimale change afin qu’elle soit supérieure à la valeur actuelle, la valeur actuelle est ensuite définie sur la nouvelle valeur minimale. Dans l’exemple, l'PropertyChangedCallback de la valeur actuelle appelle explicitement le CoerceValueCallback pour les valeurs minimales et maximales.

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

Scénarios de rappel avancés

Contraintes et valeurs souhaitées

Si une valeur définie localement d’une propriété de dépendance est modifiée par le biais de la contrainte, la valeur définie localement inchangée est conservée en tant que valeur souhaitée. Si le forçage est basé sur d’autres valeurs de propriété, le système de propriétés réévalue dynamiquement le forçage chaque fois que ces autres valeurs changent. Sous les contraintes de coercition, le système de propriétés applique la valeur la plus proche de la valeur souhaitée. Lorsque la condition de contrainte ne s'applique plus, le système de propriétés restaure la valeur souhaitée, en supposant qu'aucune valeur avec une priorité plus élevée n'est active. L’exemple suivant teste la contrainte dans la valeur actuelle, la valeur minimale et le scénario de valeur maximale.

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

Des scénarios de dépendance assez complexes peuvent se produire lorsque vous avez plusieurs propriétés dépendantes les unes des autres de manière circulaire. Techniquement, il n’existe aucun problème avec les dépendances complexes, sauf qu’un grand nombre de réévaluations peuvent réduire les performances. En outre, les dépendances complexes exposées dans l’interface utilisateur peuvent confondre les utilisateurs. Traitez PropertyChangedCallback et CoerceValueCallback aussi sans ambiguïté que possible, et ne sur-limitez pas.

Annuler les modifications de valeur

En retournant UnsetValue à partir d’un CoerceValueCallback, vous pouvez rejeter une modification de valeur de propriété. Ce mécanisme est utile lorsqu’une modification de valeur de propriété est lancée de manière asynchrone, mais lorsqu’elle est appliquée n’est plus valide pour l’état actuel de l’objet. Un autre scénario peut être de supprimer sélectivement une modification de valeur en fonction de son origine. Dans l’exemple suivant, l'CoerceValueCallback appelle la méthode GetValueSource, qui retourne une structure ValueSource avec une énumération BaseValueSource qui identifie la source de la nouvelle valeur.

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

Voir aussi