Rückrufe und Validierung von AbhängigkeitseigenschaftenDependency Property Callbacks and Validation

Dieses Thema beschreibt die Erstellung von Abhängigkeitseigenschaften mithilfe alternativer benutzerdefinierter Implementierungen für eigenschaftenbezogene Funktionen wie die Überprüfungsbestimmung, Rückrufe, die immer dann aufgerufen werden, wenn der effektive Wert der Eigenschaft geändert wird, und das Überschreiben möglicher externer Einflüsse auf die Wertbestimmung.This topic describes how to create dependency properties using alternative custom implementations for property-related features such as validation determination, callbacks that are invoked whenever the property's effective value is changed, and overriding possible outside influences on value determination. Dieses Thema enthält auch Szenarios, in denen das Erweitern des Standardverhaltens des Eigenschaftensystems mithilfe dieser Techniken geeignet ist.This topic also discusses scenarios where expanding on the default property system behaviors by using these techniques is appropriate.

Erforderliche KomponentenPrerequisites

Bei diesem Thema wird davon ausgegangen, dass Sie die grundlegenden Szenarien zum Implementieren einer Abhängigkeitseigenschaft verstehen, und Metadaten für eine benutzerdefinierte Abhängigkeitseigenschaft anwenden.This topic assumes that you understand the basic scenarios of implementing a dependency property, and how metadata is applied to a custom dependency property. Weitere Informationen finden Sie unter Benutzerdefinierte Abhängigkeitseigenschaften und Metadaten für Abhängigkeitseigenschaften.See Custom Dependency Properties and Dependency Property Metadata for context.

ÜberprüfungsrückrufeValidation Callbacks

Überprüfungsrückrufe können beim ersten Registrieren einer Abhängigkeitseigenschaft zugewiesen werden.Validation callbacks can be assigned to a dependency property when you first register it. Der Validierungs Rückruf ist nicht Teil der Eigenschafts Metadaten. Es handelt sich um eine direkte Eingabe Register der-Methode.The validation callback is not part of property metadata; it is a direct input of the Register method. Sobald ein Validierungsrückruf für eine Abhängigkeitseigenschaft erstellt wurde, kann er daher nicht durch eine neue Implementierung überschrieben werden.Therefore, once a validation callback is created for a dependency property, it cannot be overridden by a new implementation.

public static readonly DependencyProperty CurrentReadingProperty = DependencyProperty.Register(
    "CurrentReading",
    typeof(double),
    typeof(Gauge),
    new FrameworkPropertyMetadata(
        Double.NaN,
        FrameworkPropertyMetadataOptions.AffectsMeasure,
        new PropertyChangedCallback(OnCurrentReadingChanged),
        new CoerceValueCallback(CoerceCurrentReading)
    ),
    new ValidateValueCallback(IsValidReading)
);
public double CurrentReading
{
  get { return (double)GetValue(CurrentReadingProperty); }
  set { SetValue(CurrentReadingProperty, value); }
}
Public Shared ReadOnly CurrentReadingProperty As DependencyProperty =
    DependencyProperty.Register("CurrentReading",
        GetType(Double), GetType(Gauge),
        New FrameworkPropertyMetadata(Double.NaN,
            FrameworkPropertyMetadataOptions.AffectsMeasure,
            New PropertyChangedCallback(AddressOf OnCurrentReadingChanged),
            New CoerceValueCallback(AddressOf CoerceCurrentReading)),
        New ValidateValueCallback(AddressOf IsValidReading))

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

Die Rückrufe werden so implementiert, dass ihnen ein Objektwert bereitgestellt wird.The callbacks are implemented such that they are provided an object value. Sie geben true zurück, wenn der bereitgestellte Wert für die Eigenschaft gültig ist. Andernfalls geben sie false zurück.They return true if the provided value is valid for the property; otherwise, they return false. Es wird davon ausgegangen, dass die Eigenschaft entsprechend dem im Eigenschaftensystem registrierten Typ zum richtigen Typ gehört. Typüberprüfungen werden daher innerhalb von Rückrufen in der Regel nicht ausgeführt.It is assumed that the property is of the correct type per the type registered with the property system, so checking type within the callbacks is not ordinarily done. Die Rückrufe werden vom Eigenschaftensystem bei einer Vielzahl verschiedener Vorgänge verwendet.The callbacks are used by the property system in a variety of different operations. Dies schließt die anfängliche Typinitialisierung nach Standardwert, programmgesteuerte Änderung durch SetValueAufrufen von ein, oder es wird versucht, Metadaten mit einem neuen Standardwert zu überschreiben.This includes the initial type initialization by default value, programmatic change by invoking SetValue, or attempts to override metadata with new default value provided. Wenn der Validierungsrückruf von einem dieser Vorgänge aufgerufen wird und false zurückgibt, wird eine Ausnahme ausgelöst.If the validation callback is invoked by any of these operations, and returns false, then an exception will be raised. Anwendungsentwickler müssen diese Ausnahmen behandeln können.Application writers must be prepared to handle these exceptions. Rückrufen werden üblicherweise zur Validierung von Enumerationswerten oder der Einschränkung von Werten aus ganzen Zahlen oder Double-Datentypen verwendet, wenn die Eigenschaft Messungen festlegt, die 0 (null) oder höher entsprechen müssen.A common use of validation callbacks is validating enumeration values, or constraining values of integers or doubles when the property sets measurements that must be zero or greater.

Überprüfungsrückrufe sollen Klassen-Validierungssteuerelemente, keine Instanz-Validierungssteuerelemente sein.Validation callbacks specifically are intended to be class validators, not instance validators. Die Parameter des Rückrufs kommunizieren nicht mit einem bestimmten DependencyObject , auf dem die zu überprüfenden Eigenschaften festgelegt sind.The parameters of the callback do not communicate a specific DependencyObject on which the properties to validate are set. Daher sind die Validierungsrückrufe nicht nützlich für das Erzwingen der möglichen „Abhängigkeiten“, die einen Eigenschaftswert beeinflussen können, bei dem der instanzspezifische Wert einer Eigenschaft von Faktoren wie instanzspezifischen Werten anderer Eigenschaften oder dem Laufzeitzustand anhängen.Therefore the validation callbacks are not useful for enforcing the possible "dependencies" that might influence a property value, where the instance-specific value of a property is dependent on factors such as instance-specific values of other properties, or run-time state.

Im folgenden finden Sie Beispielcode für ein sehr einfaches Überprüfungs Rückruf Szenario: die Validierung, dass eine als Double primitiv typisierte Eigenschaft nicht PositiveInfinity oder NegativeInfinityist.The following is example code for a very simple validation callback scenario: validating that a property that is typed as the Double primitive is not PositiveInfinity or NegativeInfinity.

public static bool IsValidReading(object value)
{
    Double v = (Double)value;
    return (!v.Equals(Double.NegativeInfinity) && !v.Equals(Double.PositiveInfinity));
}
Public Shared Function IsValidReading(ByVal value As Object) As Boolean
    Dim v As Double = CType(value, Double)
    Return ((Not v.Equals(Double.NegativeInfinity)) AndAlso
            (Not v.Equals(Double.PositiveInfinity)))
End Function

Coerce-Wert-Rückrufe und EigenschaftenänderungsereignisseCoerce Value Callbacks and Property Changed Events

Coerce-Wert-Rückrufe übergeben die DependencyObject spezifische-Instanz für Eigenschaften, PropertyChangedCallback ebenso wie Implementierungen, die vom-Eigenschaften System aufgerufen werden, wenn sich der Wert einer Abhängigkeits Eigenschaft ändert.Coerce value callbacks do pass the specific DependencyObject instance for properties, as do PropertyChangedCallback implementations that are invoked by the property system whenever the value of a dependency property changes. Mithilfe dieser zwei Rückrufe können Sie eine Reihe von Eigenschaften für Elemente erstellen, wobei Änderungen an einer Eigenschaft eine Umwandlung oder eine erneute Auswertung von einer anderen Eigenschaft erzwingt.Using these two callbacks in combination, you can create a series of properties on elements where changes in one property will force a coercion or reevaluation of another property.

In einem typischen Szenario für die Verwendung einer Bindung von Abhängigkeitseigenschaften gibt es eine von einer Benutzerschnittstelle gesteuerte Eigenschaft, in der das Element jeweils eine Eigenschaft für den minimalen und maximalen Wert enthält, und eine dritte Eigenschaft für den tatsächlichen oder den aktuellen Wert.A typical scenario for using a linkage of dependency properties is when you have a user interface driven property where the element holds one property each for the minimum and maximum value, and a third property for the actual or current value. Wenn das Maximum in diesem Szenario so angepasst würde, dass der aktuelle Wert den neuen Maximalwert übersteigt, sollten Sie es erzwingen, dass der aktuellen Wert nicht größer sein darf als der neue Maximalwert, und eine ähnliche Beziehung für den Minimalwert und den aktuellen Wert festlegen.Here, if the maximum was adjusted in such a way that the current value exceeded the new maximum, you would want to coerce the current value to be no greater than the new maximum, and a similar relationship for minimum to current.

Im Folgenden finden Sie einen sehr kurzen Beispielcode für nur eine der drei Abhängigkeitseigenschaften, die diese Beziehung veranschaulichen.The following is very brief example code for just one of the three dependency properties that illustrate this relationship. Im Beispiel wird gezeigt, wie die CurrentReading-Eigenschaft eines Satzes aus Minimalwert/Maximalwert/aktuellem Wert von verknüpften *Reading-Eigenschaften registriert wird.The example shows how the CurrentReading property of a Min/Max/Current set of related *Reading properties is registered. Die Überprüfung wird hier wie im vorherigen Abschnitt verwendet.It uses the validation as shown in the previous section.

public static readonly DependencyProperty CurrentReadingProperty = DependencyProperty.Register(
    "CurrentReading",
    typeof(double),
    typeof(Gauge),
    new FrameworkPropertyMetadata(
        Double.NaN,
        FrameworkPropertyMetadataOptions.AffectsMeasure,
        new PropertyChangedCallback(OnCurrentReadingChanged),
        new CoerceValueCallback(CoerceCurrentReading)
    ),
    new ValidateValueCallback(IsValidReading)
);
public double CurrentReading
{
  get { return (double)GetValue(CurrentReadingProperty); }
  set { SetValue(CurrentReadingProperty, value); }
}
Public Shared ReadOnly CurrentReadingProperty As DependencyProperty =
    DependencyProperty.Register("CurrentReading",
        GetType(Double), GetType(Gauge),
        New FrameworkPropertyMetadata(Double.NaN,
            FrameworkPropertyMetadataOptions.AffectsMeasure,
            New PropertyChangedCallback(AddressOf OnCurrentReadingChanged),
            New CoerceValueCallback(AddressOf CoerceCurrentReading)),
        New ValidateValueCallback(AddressOf IsValidReading))

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

Das Eigenschaftenänderungsrückrufen für „Current“ wird verwendet, um die Änderung an andere abhängige Eigenschaften weiterzuleiten, indem explizit die Coerce-Wert-Rückrufe aufgerufen werden, die für diese anderen Eigenschaften registriert sind:The property changed callback for Current is used to forward the change to other dependent properties, by explicitly invoking the coerce value callbacks that are registered for those other properties:

private static void OnCurrentReadingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
  d.CoerceValue(MinReadingProperty);
  d.CoerceValue(MaxReadingProperty);
}
Private Shared Sub OnCurrentReadingChanged(ByVal d As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)
    d.CoerceValue(MinReadingProperty)
    d.CoerceValue(MaxReadingProperty)
End Sub

Der Coerce-Wert-Rückruf überprüft die Werte von Eigenschaften, von denen die aktuelle Eigenschaft potenziell abhängt, und erzwingt bei Bedarf den aktuellen Wert:The coerce value callback checks the values of properties that the current property is potentially dependent upon, and coerces the current value if necessary:

private static object CoerceCurrentReading(DependencyObject d, object value)
{
  Gauge g = (Gauge)d;
  double current = (double)value;
  if (current < g.MinReading) current = g.MinReading;
  if (current > g.MaxReading) current = g.MaxReading;
  return current;
}
Private Shared Function CoerceCurrentReading(ByVal d As DependencyObject, ByVal value As Object) As Object
    Dim g As Gauge = CType(d, Gauge)
    Dim current As Double = CDbl(value)
    If current < g.MinReading Then
        current = g.MinReading
    End If
    If current > g.MaxReading Then
        current = g.MaxReading
    End If
    Return current
End Function

Hinweis

Standardwerte von Eigenschaften werden nicht erzwungen.Default values of properties are not coerced. Ein Eigenschafts Wert, der dem Standardwert entspricht, kann auftreten, wenn ein Eigenschafts Wert noch seinen ursprünglichen Standardwert aufweist oder ClearValuewenn andere Werte mit gelöscht werden.A property value equal to the default value might occur if a property value still has its initial default, or through clearing other values with ClearValue.

Der Coerce-Wert und die Eigenschaftenänderungsrückrufen sind Teil der Eigenschaftenmetadaten.The coerce value and property changed callbacks are part of property metadata. Da die Rückrufe für eine bestimmte Abhängigkeitseigenschaft auf einem Typ vorhanden sind, die von dem Typ abgeleitet ist, der die Abhängigkeitseigenschaft besitzt, können sie von Ihnen geändert werden, indem die Metadaten für diese Eigenschaft auf Ihrem Typ überschrieben werden.Therefore, you can change the callbacks for a particular dependency property as it exists on a type that you derive from the type that owns the dependency property, by overriding the metadata for that property on your type.

Erweiterte Umwandlung und RückrufszenariosAdvanced Coercion and Callback Scenarios

Einschränkungen und gewünschte WerteConstraints and Desired Values

Die CoerceValueCallback Rückrufe werden vom Eigenschaften System verwendet, um einen Wert in Übereinstimmung mit der von Ihnen deklarierten Logik umzuwandeln, aber der erzwungene Wert einer lokal festgelegten Eigenschaft behält intern weiterhin einen "gewünschten Wert" bei.The CoerceValueCallback callbacks will be used by the property system to coerce a value in accordance to the logic you declare, but a coerced value of a locally set property will still retain a "desired value" internally. Wenn die Einschränkungen auf anderen Eigenschaftswerten basieren, kann sich dies während der Lebensdauer der Anwendung dynamisch ändern. Die Umwandlungseinschränkungen werden auch dynamisch geändert, und die eingeschränkte Eigenschaft kann ihren Wert ändern, um sich unter den gegebenen neuen Einschränkungen so stark wie möglich dem gewünschten Wert anzunähern.If the constraints are based on other property values that may change dynamically during the application lifetime, the coercion constraints are changed dynamically also, and the constrained property can change its value to get as close to the desired value as possible given the new constraints. Der Wert entspricht dem gewünschten Wert, wenn alle Einschränkungen aufgehoben werden.The value will become the desired value if all constraints are lifted. Sie können möglicherweise einige recht komplizierte Abhängigkeitsszenarios einführen, wenn Sie über mehrere Eigenschaften verfügen, die zirkulär voneinander abhängig sind.You can potentially introduce some fairly complicated dependency scenarios if you have multiple properties that are dependent on one another in a circular manner. Beispielsweise könnten der Minimal- und Maximalwert im Szenario zum Minimalwert/Maximalwert/aktuellen Wert vom Benutzer einstellbar sein.For instance, in the Min/Max/Current scenario, you could choose to have Minimum and Maximum be user settable. Wenn dies der Fall ist, müssen Sie erzwingen, dass der Maximalwert immer größer als Minimalwert ist und umgekehrt.If so, you might need to coerce that Maximum is always greater than Minimum and vice versa. Wenn diese Umwandlung aber aktiv ist und der Maximalwert in den Minimalwert umgewandelt wird, bleibt „Current“ in einem nicht festlegbaren Zustand, da es von beiden abhängt und auf den Bereich zwischen den Werten, der 0 (null) entspricht, eingeschränkt ist.But if that coercion is active, and Maximum coerces to Minimum, it leaves Current in an unsettable state, because it is dependent on both and is constrained to the range between the values, which is zero. Wenn der Maximal- oder Minimalwert dann angepasst wurde, scheint „Current“ einem dieser Werte zu „folgen“, da der gewünschte Wert von „Current“ noch immer gespeichert ist und versucht, den gewünschten Wert zu erreichen, während die Einschränkungen gelockert werden.Then, if Maximum or Minimum are adjusted, Current will seem to "follow" one of the values, because the desired value of Current is still stored and is attempting to reach the desired value as the constraints are loosened.

Technisch gesehen gibt es keine Kritik an komplexen Abhängigkeiten. Allerdings können sie leichte Leistungseinbußen mit sich bringen, wenn sie eine große Anzahl von erneuten Auswertung erfordern, und Benutzer verwirren, wenn sie die Benutzeroberfläche direkt beeinflussen.There is nothing technically wrong with complex dependencies, but they can be a slight performance detriment if they require large numbers of reevaluations, and can also be confusing to users if they affect the UI directly. Seien Sie vorsichtig bei Eigenschaftenänderungs- und Coerce-Wert-Rückrufen, und stellen Sie sicher, dass die versuchte Umwandlung so eindeutig wie möglich behandelt werden kann und nicht übermäßig einschränkt.Be careful with property changed and coerce value callbacks and make sure that the coercion being attempted can be treated as unambiguously as possible, and does not "overconstrain".

Abbrechen von Wertänderungen mit CoerceValueUsing CoerceValue to Cancel Value Changes

Das Eigenschaften System behandelt alle CoerceValueCallback , die den Wert UnsetValue als Sonderfall zurückgibt.The property system will treat any CoerceValueCallback that returns the value UnsetValue as a special case. Dieser Sonderfall bedeutet, dass die Eigenschaften Änderung, die dazu CoerceValueCallback geführt hat, dass das aufgerufen wird, vom Eigenschaften System abgelehnt werden sollte und dass das Eigenschaften System stattdessen den vorherigen Wert der Eigenschaft melden sollte.This special case means that the property change that resulted in the CoerceValueCallback being called should be rejected by the property system, and that the property system should instead report whatever previous value the property had. Dieser Mechanismus kann bei der Überprüfung hilfreich sein, dass asynchron initiierte Änderungen an einer Eigenschaft für den aktuellen Objektzustand noch gültig sind, sowie bei der Unterdrückung dieser Änderungen, sofern sie nicht gültig sind.This mechanism can be useful to check that changes to a property that were initiated asynchronously are still valid for the current object state, and suppress the changes if not. Ein anderes mögliches Szenario ist die selektive Unterdrückung eines Werts, je nachdem welche der Komponenten der Eigenschaftswertermittlung für den gemeldeten Wert verantwortlich ist.Another possible scenario is that you can selectively suppress a value depending on which component of property value determination is responsible for the value being reported. Zu diesem Zweck können Sie den DependencyProperty im Rückruf und den Eigenschaften Bezeichner als Eingabe für GetValueSourceden-Wert verwenden und dann verarbeiten ValueSource.To do this, you can use the DependencyProperty passed in the callback and the property identifier as input for GetValueSource, and then process the ValueSource.

Siehe auchSee also