Silverlight: отсутствует DependencyObject.CoerceValue - PullRequest
1 голос
/ 01 июля 2011

В Silverlight нет DependencyObject.CoerceValue.Я ищу альтернативу, чтобы сделать следующий WPF-код также в Silverlight.

Ситуация: существует класс Range, который имеет несколько DependencyProperties: MinimumProperty, MaximumProperty, LowerValueProperty и UpperValueProperty.

Минимум никогда не может превышать Максимум, Максимум никогда не должен быть меньше Минимума.Более того, LowerValue и UpperValue должны находиться между минимальным и максимальным значениями, тогда как LowerValue всегда меньше UpperValue.

Все свойства DependencyProperties реализованы следующим образом (в WPF):

public static new readonly DependencyProperty MinimumProperty =
     DependencyProperty.Register("Minimum",
     typeof(double),
     typeof(Range),
     new FrameworkPropertyMetadata(0d,
       new PropertyChangedCallback(Range.OnMinimumChanged),
       new CoerceValueCallback(Range.CoerceMinimum)),
     new ValidateValueCallback(Range.ValidateMinimum));

public new double Minimum
    {
      get { return (double)base.GetValue(MinimumProperty); }
      set { base.SetValue(MinimumProperty, value); }
    }

Приведение в WPFделается так:

private static object CoerceMinimum(DependencyObject source, object value)
{
  Range r = source as Range;
  double maximum = r.Maximum;
  double val = (double)value;
  if (val > maximum)
  {
    return maximum;
  }
  return value;
}

PropertyChangedCallback выглядит следующим образом:

private static void OnMinimumChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
{
  Range r = source as Range;
  r.CoerceValue(LowerValueProperty);
  r.CoerceValue(UpperValueProperty);
  r.CoerceValue(MaximumProperty);
}

ValidateValueCallback в данном случае не имеет значения.Другие обратные вызовы похожи на показанный код.

В WPF это работает хорошо.Например я установил (в XAML)

<Range LowerValue="12" Minimum="10" UpperValue="15" Maximum="20" />

все значения верны.Порядок не имеет значения!

Но в Silverlight я его не запускаю.

Первый шаг - это обходной путь для CoerceValueCallback.Я поднимаю приведение в PropertyChangedCallback, например:

private static void OnMinimumChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
{
  Range r = source as Range;
  double newVal = (double)e.NewValue;
  double coercedVal = (double)CoerceMinimum(source, newVal);
  if (coercedVal != newVal)
  {
    r.Minimum = coercecVal;
    return;
  }

  r.CoerceValue(LowerValueProperty);
  r.CoerceValue(UpperValueProperty);
  r.CoerceValue(MaximumProperty);
}

Если теперь для Minimum установлено значение, CoerceMinimum все еще выполняется, а минимальное приведение выполнено хорошо.

Но последнеетри строки не компилируются, потому что DependencyObject не имеет метода CoerceValue.И это именно та позиция, в которой я нахожусь в тупике.

Как повысить Coercion для LowerValue, UpperValue и Maximum на MinimumChanged?Или есть другой способ убедиться, что порядок инициализации не имеет значения и все свойства установлены правильно (при условии, что условие выполнено)?

Заранее спасибо!

1 Ответ

0 голосов
/ 04 июля 2011

У меня есть решение :) Я уверен, оно еще не завершено.Я все еще отлаживаю все возможные ордера, но я думаю, что большинство уже сделали.

Я выкладываю только код для LowerValue, остальные почти такие же:

  • OnUpperValueChangedи CoerceLowerValueChanged.
  • OnMinimumChanged повысить CoerceMinimum, CoerceUpperValueChanged и CoerceLowerValueChanged.
  • OnMaximumChanged Повышение CoerceMaximum, CoerceUpperValueChanged и CoerceLowerValueChanged.

Приведение минимума и максимума просто легко.Если новое значение больше максимального (или меньше минимального), принимайте максимальное (или минимальное), в противном случае принимайте новое значение.

Вот код:

private static void OnLowerValueChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
{
  Range r = source as Range;

  if (r._levelsFromRootCall == 0)
  {
    r._requestedLowerVal = (double)e.NewValue;
  }

  r._levelsFromRootCall++;
  r.CoerceLowerValue();

  r.CoerceUpperValue();
  r._levelsFromRootCall--;
}

private void CoerceLowerValue()
{
  double minimum = this.Minimum;
  double maximum = this.Maximum;
  double lowerVal = this.LowerValue;
  double upperVal = this.UpperValue;
  if (lowerVal != _requestedLowerVal && _requestedLowerVal >= minimum && _requestedLowerVal <= maximum)
  {
    if (_requestedLowerVal <= upperVal)
    {
      base.SetValue(LowerValueProperty, _requestedLowerVal);
    }
    else
    {
      base.SetValue(LowerValueProperty, upperVal);
    }
  }
  else
  {
    if (lowerVal < minimum)
    {
      base.SetValue(LowerValueProperty, minimum);
    }
    else if (lowerVal > upperVal || _requestedLowerVal > upperVal)
    {
      base.SetValue(LowerValueProperty, upperVal);
    }
    else if (lowerVal > maximum)
    {
      base.SetValue(LowerValueProperty, maximum);
    }
  }
}
...