Как мне вернуть DependencyProperty обратно к его значению по умолчанию в XAML - PullRequest
0 голосов
/ 28 июля 2010

Я использую настраиваемое пользователем Effect с помощью ползунков, и у меня есть кнопка сброса рядом с ползунком. Идея состоит в том, чтобы позволить пользователю вернуться к значению по умолчанию свойства Effect, как указано в метаданных.

Я думаю, что это может быть тривиально в XAML.

Ответы [ 2 ]

4 голосов
/ 29 июля 2010

Свойства зависимости не имеют значений по умолчанию. Если свойство зависимости не имеет локального значения, оно получит свое значение либо путем наследования значения, либо путем принуждения, в зависимости от того, как свойство было реализовано.

Вы действительно не можете избавиться от локального значения свойства в XAML - это потребует от вас вызова ClearValue для свойства, и нет способа найти объект и вызвать метод декларативно для него. Но до тех пор, пока свойство получает свое значение посредством наследования значения (вместо приведения значения) - вы можете достичь в основном той же цели, привязав свойство к свойству, от которого оно наследует, у соответствующего предка

Например, вот стиль, который вы бы использовали, чтобы создать ListBox, который устанавливает цвет переднего плана всех элементов, которые не выбраны :

<ListBox.ItemContainerStyle>
  <Style TargetType="ListBoxItem">
    <Setter Property="Foreground" Value="Red"/>
    <Style.Triggers>
        <Trigger Property="IsSelected" Value="True">
            <Setter 
               Property="Foreground" 
               Value="{Binding 
                  RelativeSource={RelativeSource FindAncestor, AncestorType=ListBox},
                  Path=Foreground}" />
        </Trigger>
    </Style.Triggers>
  </Style>
</ListBox.ItemContainerStyle>

Это в основном явно реализует наследование значений через связывание. Это означает, что свойство ListBoxItem.Foreground теперь имеет локальное значение, и что всякий раз, когда вы изменяете свойство Foreground для ListBox, оно связывает, обновляет ListBoxItem.Foreground, а не свойство зависимости система. Это может иметь значение, если в вашем ListBox есть сотни тысяч предметов. Но в большинстве реальных случаев вы никогда не заметите разницу.

1 голос
/ 24 июня 2017

Чтобы избежать логических циклов, WPF решительно сопротивляется попыткам установить значение DependencyProperty в его текущее значение. Это проблема во время инициализации, когда вы хотите, чтобы зависимая логика запускалась для установки всего в первый раз на основе DefaultValue, записанного в метаданных, для каждого из различных зависимых свойств. WPF этого не сделает, потому что, в особом случае, все эти свойства уже получают значения по умолчанию, даже не выполнив никакой такой логики.

Насколько я могу судить, ни одна комбинация InvalidateProperty, CoerceValue или ClearValue не убедит WPF выполнить эту работу. Тривиальным решением было бы каким-то образом вызвать безнадежно безопасное значение, отличное от значения по умолчанию, чтобы изменить его на, а затем сбросить значение с помощью ClearValue. Это кажется хакерским, поскольку определение «безвредной» ценности может оказаться непрактичным. Возможно, еще хуже, этот подход излишне будет волновать граф зависимостей дважды, а не один раз.

В качестве, возможно, более элегантного решения вы можете вызвать следующий метод расширения в конструкторе каждого соответствующего объекта, чтобы вручную вызвать логику PropertyChanged для каждого DependencyProperty, для которого необходимо распространить свои изменения. Этот помощник будет инициировать последующие изменения в соответствии со значением по умолчанию, хранящимся в соответствующих метаданных.

public static void ResetValue(this DependencyObject _this, DependencyProperty dp)
{
    var md = dp.GetMetadata(_this.GetType());
    if (_this.GetValue(dp).Equals(md.DefaultValue))
    {
        var args = new DependencyPropertyChangedEventArgs(dp, DependencyProperty.UnsetValue, md.DefaultValue);
        md.PropertyChangedCallback(_this, args);
    }
    else
        _this.ClearValue(dp);
}

Как показано, функция включает проверку, чтобы увидеть, будет ли ClearValue действительно эффективным, поэтому помимо сценариев инициализации вы также можете использовать эту функцию в качестве замены для ClearValue в целом. Для наглядности демонстрации этот метод не проверяет, что хост-объект фактически предоставляет какую-либо логику изменения свойств, но это было бы простым изменением. В C # 7, например:

        // ...
        md.PropertyChangedCallback?.Invoke(_this, args);

Пример использования в вашем классе:

class MyClass : DependencyObject
{
    public static readonly DependencyProperty MyDp = /* ... */

    public MyClass()
    {
        this.ResetValue(MyDp);
        /* ... */
    }
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...