Проверка и обратные вызовы свойства зависимостей
В этом разделе описывается создание свойства зависимостей с помощью альтернативных пользовательских реализаций функций, связанных со свойствами, таких как определение проверки, обратные вызовы, которые совершаются при каждом изменении эффективного значения свойства, и переопределение возможных внешних влияний на определение значения. В этом разделе также рассматриваются сценарии, в которых подходит расширение стандартных правил для системы свойств с помощью этих методов.
Предварительные требования
В этом разделе предполагается, что вы понимаете основные сценарии реализации свойства зависимостей и способы применения метаданных к настраиваемому свойству зависимостей. Дополнительные сведения см. в разделах Пользовательские свойства зависимостей и Метаданные свойства зависимостей.
Обратные вызовы проверки
Обратные вызовы проверки можно назначить свойству зависимостей при первой регистрации. Обратный вызов проверки не является частью метаданных свойства; Это прямой ввод Register метод. Поэтому после того, как будет создан обратный вызов проверки для свойства зависимостей, он уже не может быть переопределен новой реализацией.
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); }
}
Обратные вызовы реализуются так, что они получают значение объекта. Они возвращают true
, если полученное значение является допустимым для свойства. В противном случае — возвращают false
. Предполагается, что свойство принадлежит допустимому типу (зарегистрированному в системе свойств), поэтому проверка типов в обратных вызовах обычно не выполняется. Обратные вызовы используются системой свойств в различных операциях. Сюда входят инициализация типов по значению по умолчанию, программное изменение путем вызова SetValue, или попытка переопределить метаданные с помощью нового значения по умолчанию. Если обратный вызов проверки совершается любой из этих операций и возвращает false
, вызывается исключение. Программисты должны быть готовы обрабатывать эти исключения. Обычно обратные вызовы проверки используются для проверки значений перечислений или для ограничения значений целых чисел, когда это свойство задает измерения, которые должны быть больше или равны нулю.
Обратные вызовы проверки специально предназначены для проверки классов, а не экземпляров классов. Параметры обратного вызова не взаимодействуют между собой определенным DependencyObject на какой набор свойств, которые необходимо проверить. Поэтому обратные вызовы проверки не используются для принудительного применения возможных "зависимостей", способных повлиять на значение свойства, где значение свойства для этого экземпляра зависит от таких факторов, как значения других свойств этого экземпляра или состояния во время выполнения.
Ниже приведен пример кода для обратного вызова сценария очень простой проверки: проверка того, свойства, который типизируется как Double -примитив не PositiveInfinity или NegativeInfinity.
public static bool IsValidReading(object value)
{
Double v = (Double)value;
return (!v.Equals(Double.NegativeInfinity) && !v.Equals(Double.PositiveInfinity));
}
Обратные вызовы с привязкой к значению и события изменения свойств
Приведение значения обратных вызовов передают определенный DependencyObject экземпляр для свойств PropertyChangedCallback реализации, которые вызываются системой свойств при каждом изменении значения свойства зависимостей. Используя сочетание этих обратных вызовов, можно создать ряд свойств элементов, где изменения значения одного свойства будут вызывать принудительное изменение или пересчет значения другого свойства.
Вот типичный сценарий использования связки свойств зависимостей. Имеется свойство, управляемое пользовательским интерфейсом. Элемент содержит по одному свойству для минимального и максимального значений и третье свойство для фактического или текущего значения. Если максимальное значение будет изменено так, что текущее значение станет превышать это новое максимальное значение, следует изменить текущее значение, сделав его не более максимального. Аналогичная связь нужна и для минимального значения.
Ниже приведен пример очень краткого кода для одного из трех свойств зависимостей, иллюстрирующий эту связь. В примере показано, как регистрируется свойство CurrentReading
для набора связанных свойств (максимальное, минимальное, текущее) объекта *Reading. Он использует проверку, как это показано в предыдущем разделе.
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); }
}
Обратный вызов при изменении свойства текущего объекта используется для пересылки изменений в другие зависимые свойства путем явного выполнения обратных вызовов с привязкой к значению, зарегистрированных для этих свойств.
private static void OnCurrentReadingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
d.CoerceValue(MinReadingProperty);
d.CoerceValue(MaxReadingProperty);
}
При выполнении обратных вызовов с привязкой к значению проверяются значения свойств, от которых потенциально зависит текущее свойство, и принудительно изменяется его значение при необходимости.
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;
}
Note
Значения свойств по умолчанию не изменяются. Значение свойства равно значению по умолчанию может произойти, если значение свойства по-прежнему имеет его первоначальное значение по умолчанию, или через Очистка других значений с ClearValue.
Обратные вызовы с привязкой к значению и обратные вызовы при изменении свойств являются частью метаданных свойства. Вы можете изменить обратные вызовы для конкретного свойства зависимостей, так как оно задается типом, производным от типа, которому принадлежит свойство зависимостей, путем переопределения метаданных для этого свойства в типе.
Сценарии расширенного приведения и обратного вызова
Ограничения и требуемые значения
CoerceValueCallback Обратных вызовов, которая будет использоваться системой свойств для присвоения значения в соответствии с логикой, но приведенное значение локально заданного свойства будет по-прежнему внутренне сохранять «требуемое значение». Если ограничения зависят от других значений свойств, которые могут изменяться динамически во время работы приложения, приведенные ограничения будут также изменяться динамически, а ограниченное свойство может изменить свое значение, чтобы максимально приблизиться к требуемому значению с учетом новых ограничений. Значение станет равно требуемому значению, если все ограничения будут сняты. При необходимости можно создать достаточно сложные сценарии зависимостей, если имеется, например, несколько свойств, которые циклически зависят друг от друга. В сценарии, где имеется минимальное, максимальное и текущее значения, можно, например, сделать минимальное и максимальное значения определяемыми пользователем. В этом случае может потребоваться правило приведения, определяющее, что максимальное значение должно быть всегда больше минимального или наоборот. Но если приведение включено и максимальное значение приводится к минимальному, текущее значение остается в неопределенном состоянии, так как оно зависит от них обоих и ограничено диапазоном между ними, который равен нулю. С другой стороны, если максимальное или минимальное значение настраивается, текущее значение будет стремиться "отслеживать" одно из них. Это происходит из-за того, что для текущего значения сохраняется его требуемая величина и оно пытается достичь этой величины при ослаблении ограничений.
С технической реализацией сложных зависимостей нет проблем, но они могут ухудшить производительность, если для их осуществления потребуется выполнять большой объем вычислений. Кроме того, они могут вызвать недоумение у пользователей, если будут непосредственно влиять на пользовательский интерфейс. Будьте внимательны при использовании обратных вызовов с привязкой к значению и обратных вызовов при изменении свойств и следите за тем, чтобы попытки приведения могли выполняться максимально однозначно, не вызывая "сверхограничений".
Использование CoerceValue для отмены изменений значения
Система свойств будет рассматривать любой CoerceValueCallback , возвращающий значение UnsetValue как особый случай. Это особый случай означает, что изменение свойства, которое привело к CoerceValueCallback должно быть отклонено системой свойств, и система свойств вместо этого может сообщить предыдущее значение свойства. Этот механизм можно использовать для того, чтобы убедиться, что изменения свойства, инициированные асинхронно, все еще действительны для текущего состояния объекта, и, если это не так, запретить эти изменения. Другой возможный сценарий. Вы можете выборочно запретить значения в зависимости от того, какой компонент определения значения свойства отвечает за переданное значение. Чтобы сделать это, можно использовать DependencyProperty переданной функции обратного вызова и идентификатор свойства как входные данные для GetValueSource, а затем обработать ValueSource.