Zależność wartości wywołania zwrotnego i walidacjiDependency Property Callbacks and Validation

W tym temacie opisano sposób tworzenia właściwości zależności przy użyciu alternatywnych implementacji niestandardowych dla funkcji związanych z właściwościami, takich jak określanie sprawdzania poprawności, wywołania zwrotne, które są wywoływane po zmianie efektywnej wartości właściwości i zastępowanie wpływ na ustalanie wartości.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. W tym temacie omówiono również scenariusze, w których rozszerzanie domyślnych zachowań systemowych właściwości przy użyciu tych technik jest odpowiednie.This topic also discusses scenarios where expanding on the default property system behaviors by using these techniques is appropriate.

Wymagania wstępnePrerequisites

W tym temacie przyjęto założenie, że rozumiesz podstawowe scenariusze implementacji właściwości zależności i jak metadane są stosowane do właściwości zależności niestandardowej.This topic assumes that you understand the basic scenarios of implementing a dependency property, and how metadata is applied to a custom dependency property. Zobacz Właściwości zależności niestandardowej i metadane właściwości zależności dla kontekstu.See Custom Dependency Properties and Dependency Property Metadata for context.

Wywołania zwrotne sprawdzania poprawnościValidation Callbacks

Wywołania zwrotne sprawdzania poprawności można przypisać do właściwości zależności przy pierwszym zarejestrowaniu go.Validation callbacks can be assigned to a dependency property when you first register it. Wywołanie zwrotne sprawdzania poprawności nie jest częścią metadanych właściwości; jest to bezpośrednie wejście Register metody.The validation callback is not part of property metadata; it is a direct input of the Register method. W związku z tym po wywołaniu zwrotnym sprawdzania poprawności jest tworzony dla właściwości zależności, nie można zastąpić przez nową implementację.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

Wywołania zwrotne są implementowane w taki sposób, że są one dostarczane wartość obiektu.The callbacks are implemented such that they are provided an object value. Zwracają, true jeśli podana wartość jest ważna dla właściwości; w przeciwnym falserazie wrócą .They return true if the provided value is valid for the property; otherwise, they return false. Zakłada się, że właściwość jest odpowiedniego typu dla typu zarejestrowanego w systemie właściwości, więc sprawdzanie typu w wywołaniach zwrotnych zwykle nie jest wykonywane.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. Wywołania zwrotne są używane przez system właściwości w różnych operacjach.The callbacks are used by the property system in a variety of different operations. Obejmuje to początkową inicjację typu domyślną, SetValuezmianę programową przez wywołanie lub próby zastąpienia metadanych nową wartością domyślną.This includes the initial type initialization by default value, programmatic change by invoking SetValue, or attempts to override metadata with new default value provided. Jeśli wywołanie zwrotne sprawdzania poprawności jest wywoływane falseprzez dowolną z tych operacji i zwraca , następnie zostanie zgłoszony wyjątek.If the validation callback is invoked by any of these operations, and returns false, then an exception will be raised. Autorzy aplikacji muszą być przygotowani do obsługi tych wyjątków.Application writers must be prepared to handle these exceptions. Typowym zastosowaniem wywołań zwrotnych sprawdzania poprawności jest sprawdzanie poprawności wartości wyliczania lub ograniczanie wartości liczby całkowitej lub podwaja, gdy właściwość ustawia pomiary, które muszą być zerowe lub większe.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.

Wywołania zwrotne sprawdzania poprawności w szczególności są przeznaczone do sprawdzania poprawności klasy, a nie incewatory wystąpienia.Validation callbacks specifically are intended to be class validators, not instance validators. Parametry wywołania zwrotnego nie komunikują się z określonymi DependencyObject właściwościami do sprawdzenia poprawności.The parameters of the callback do not communicate a specific DependencyObject on which the properties to validate are set. W związku z tym wywołania zwrotne sprawdzania poprawności nie są przydatne do wymuszania możliwych "zależności", które mogą mieć wpływ na wartość właściwości, gdzie wartość właściwości specyficzne dla wystąpienia jest zależna od czynników, takich jak wartości specyficzne dla wystąpienia innych właściwości lub stanu czasu wykonywania.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.

Poniżej przedstawiono przykładowy kod dla bardzo prostego scenariusza wywołania zwrotnego sprawdzania poprawności: sprawdzanie poprawności, że właściwość, która jest wpisywany jako Double pierwotny nie PositiveInfinity jest lub NegativeInfinity.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

Wywołanie zwrotne wartości wymuszonej i zdarzenia zmiany właściwościCoerce Value Callbacks and Property Changed Events

Wywołania zwrotne wartości wymuszania przekazać określonego DependencyObject PropertyChangedCallback wystąpienia dla właściwości, podobnie jak implementacje, które są wywoływane przez system właściwości, gdy zmienia się wartość właściwości zależności.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. Za pomocą tych dwóch wywołań zwrotnych w połączeniu, można utworzyć serię właściwości na elementy, gdzie zmiany w jednej właściwości wymusi przymusu lub ponownej oceny innej właściwości.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.

Typowy scenariusz przy użyciu powiązania właściwości zależności jest, gdy masz właściwości oparte na interfejsie użytkownika, gdzie element posiada jedną właściwość dla wartości minimalnej i maksymalnej i trzeciej właściwości dla wartości rzeczywistej lub bieżącej.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. W tym miejscu, jeśli maksymalna została dostosowana w taki sposób, że bieżąca wartość przekroczyła nowe maksimum, należy wymuszać bieżącą wartość nie większą niż nowe maksimum i podobną relację dla minimalnej do bieżącej.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.

Poniżej przedstawiono bardzo krótki przykładowy kod tylko dla jednej z trzech właściwości zależności, które ilustrują tę relację.The following is very brief example code for just one of the three dependency properties that illustrate this relationship. W przykładzie CurrentReading pokazano, jak jest rejestrowana właściwość zestawu Min/Max/Current powiązanych właściwości *Odczytu.The example shows how the CurrentReading property of a Min/Max/Current set of related *Reading properties is registered. Używa sprawdzania poprawności, jak pokazano w poprzedniej sekcji.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

Właściwość zmieniona wywołania zwrotnego dla Current jest używany do przekazywania zmian do innych właściwości zależnych, jawnie wywołując wywołania zwrotne wartości wymuszania, które są zarejestrowane dla tych innych właściwości: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

Wywołanie zwrotne wartości wmusu sprawdza wartości właściwości, od których potencjalnie zależy bieżąca właściwość, i w razie potrzeby wymusza bieżącą wartość: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

Uwaga

Domyślne wartości właściwości nie są wymuszane.Default values of properties are not coerced. Wartość właściwości równa wartości domyślnej może wystąpić, jeśli wartość właściwości nadal ma początkową wartość domyślną lub poprzez wyczyszczenie innych wartości za pomocą pliku ClearValue.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.

Wartość wmusu i właściwości zmienione wywołania zwrotne są częścią metadanych właściwości.The coerce value and property changed callbacks are part of property metadata. W związku z tym można zmienić wywołania zwrotne dla właściwości określonej zależności, ponieważ istnieje na typ, który pochodzi od typu, który jest właścicielem właściwości zależności, zastępując metadane dla tej właściwości na typ.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.

Zaawansowane scenariusze przymusu i wywołania zwrotnegoAdvanced Coercion and Callback Scenarios

Wiązania i żądane wartościConstraints and Desired Values

Wywołania CoerceValueCallback zwrotne będą używane przez system właściwości do wymuszania wartości zgodnie z logiką, którą deklarujesz, ale wymuszona wartość właściwości ustawionej lokalnie nadal będzie zachowywać "żądaną wartość" wewnętrznie.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. Jeśli ograniczenia są oparte na innych wartościach właściwości, które mogą zmieniać się dynamicznie w okresie istnienia aplikacji, ograniczenia przymusu są również zmieniane dynamicznie, a właściwość ograniczona może zmienić jej wartość, aby zbliżyć się do żądanej wartości, jak możliwe, biorąc pod uwagę nowe ograniczenia.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. Wartość stanie się żądaną wartością, jeśli wszystkie ograniczenia zostaną zniesione.The value will become the desired value if all constraints are lifted. Potencjalnie można wprowadzić niektóre scenariusze zależności dość skomplikowane, jeśli masz wiele właściwości, które są zależne od siebie w sposób cykliczny.You can potentially introduce some fairly complicated dependency scenarios if you have multiple properties that are dependent on one another in a circular manner. Na przykład w scenariuszu Min/Max/Current można wybrać opcję Ustawienia minimalnego i maksymalnego użytkownika.For instance, in the Min/Max/Current scenario, you could choose to have Minimum and Maximum be user settable. Jeśli tak, może być konieczne wymuszenia, że maksymalna jest zawsze większa niż minimalna i odwrotnie.If so, you might need to coerce that Maximum is always greater than Minimum and vice versa. Ale jeśli ten przymus jest aktywny, a Maksymalne wymusza do minimum, pozostawia Current w stanie unsettable, ponieważ jest zależny od obu i jest ograniczona do zakresu między wartościami, który jest zerowy.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. Następnie, jeśli maksymalna lub minimalna są dostosowane, Current wydaje się "śledzić" jedną z wartości, ponieważ żądana wartość Current jest nadal przechowywane i próbuje osiągnąć żądaną wartość, jak ograniczenia są poluzowane.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.

Nie ma nic technicznie nie tak ze złożonymi zależnościami, ale mogą one być niewielkie szkody wydajności, jeśli wymagają one dużej liczby ponownych wycen, a także może być mylące dla użytkowników, jeśli mają one wpływ na interfejs użytkownika bezpośrednio.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. Należy zachować ostrożność przy zmianie właściwości i wymuszać wartość wywołania zwrotnego i upewnij się, że przymus podejmowana próba może być traktowane tak jednoznacznie, jak to możliwe i nie "przepełnienie".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".

Używanie funkcji CoerceValue do anulowania zmian wartościUsing CoerceValue to Cancel Value Changes

System właściwości będzie CoerceValueCallback traktować każdy, UnsetValue który zwraca wartość jako przypadek szczególny.The property system will treat any CoerceValueCallback that returns the value UnsetValue as a special case. Ten szczególny przypadek oznacza, że zmiana CoerceValueCallback właściwości, która spowodowała wywołanie powinny zostać odrzucone przez system właściwości i że system właściwości powinien zamiast tego zgłosić niezależnie od poprzedniej wartości właściwości.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. Ten mechanizm może być przydatne, aby sprawdzić, czy zmiany do właściwości, które zostały zainicjowane asynchronicznie są nadal prawidłowe dla bieżącego stanu obiektu i pominąć zmiany, jeśli nie.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. Innym możliwym scenariuszem jest selektywne pomijanie wartości w zależności od tego, który składnik wartości właściwości jest odpowiedzialny za wartość zgłaszaną.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. Aby to zrobić, można DependencyProperty użyć przekazanych w wywołaniu zwrotnym GetValueSourcei identyfikatorze ValueSourcewłaściwości jako dane wejściowe dla , a następnie przetworzyć .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.

Zobacz teżSee also