Привязка IsEnabled и других свойств к открытым свойствам, работает ли она как свойства зависимости? - PullRequest
1 голос
/ 18 ноября 2009

В моем сценарии у меня много кнопок или других элементов управления, которые я хочу зависеть от открытого свойства внутри файла code-behind. Давайте назовем это IsEverythingLoaded и это логическое значение.

Теперь мне бы хотелось, чтобы кнопка выглядела так

<Button Click="DoTheMagic" 
     IsEnabled="{Binding Path=IsEverythingLoaded}">Click Me</Button>

Чтобы даже запустить это, я понял, что мне нужно указать его на Относительный источник, поэтому, добавив это к моему <Window> заявлению, я получил инициацию и визуализацию для работы.

DataContext="{Binding RelativeSource={RelativeSource Self}}"

Однако, допустим, что я вызываю событие с другой кнопкой, которая затем должна была установить IsEverythingLoaded на true, я бы предположил, что IsEnabled на каждой кнопке тоже. И поэтому снова кликабельны, но я ошибся, разве не так должны работать DependencyProperties?

Для уточнения ..

Я НЕ хочу написать IsEverythingLoaded в качестве свойства зависимости. Я хочу, чтобы кнопка до зависела от A CLR Property

Ответы [ 3 ]

4 голосов
/ 18 ноября 2009

Ваша кнопка (т. Е. Привязка к данным) должна быть уведомлена об изменении вашей общедоступной собственности. Это можно сделать двумя способами:

  • Пусть ваш класс реализует INotifyPropertyChanged и вызовет событие PropertyChanged после изменения IsEverythingLoaded или
  • делает ваше общедоступное свойство DependencyProperty, и в этом случае уведомление выполняется платформой автоматически. Страница DependencyProperty MSDN содержит дополнительные пояснения и пример того, как это сделать.

Для первого варианта Томас написал пример; для второго варианта ваш код будет выглядеть так:

public static readonly DependencyProperty IsEverythingLoadedProperty =
    DependencyProperty.Register("IsEverythingLoaded", typeof(Boolean),
                                 typeof(YourCodeBehindClass), new PropertyMetadata(false));

public Boolean IsEverythingLoaded {
    get { return (Boolean)this.GetValue(IsEverythingLoadedProperty); }
    set { this.SetValue(IsEverythingLoadedProperty, value); } 
}
4 голосов
/ 19 ноября 2009

Я категорически не согласен с вашим общим утверждением, что связывание DP -> DP - это «плохой дизайн».

Вот несколько причин, по которым связывание DP -> DP можно считать хорошим дизайном, а не плохим:

  1. Привязка свойства DependencyProperty к другому DependencyProperty намного эффективнее , чем привязка его к свойству CLR, которое реализует INotifyPropertyChanged. Этот вариант использования был в значительной степени оптимизирован в WPF и именно так вы и ожидаете.

  2. DependencyProperties гораздо менее подвержены ошибкам для синхронизации данных. Очень легко забыть вызвать событие PropertyChanged или неправильно проанализировать все ситуации, в которых вам может понадобиться вызвать его. DependencyProperties избавит вас от этого бремени. Так как я переключился с использования INotifyPropertyChanged в первую очередь на использование DependencyProperties, мои ошибки рассинхронизации данных уменьшились, возможно, в 100 раз почти до нуля, а те, которые почти всегда остаются, находятся в коде INotifyPropertyChanged.

  3. При написании демонстраций своего кода вы часто неожиданно сталкиваетесь с необходимостью анимировать то, что вы всегда рассматривали как чистое свойство «данных». Если это не DependencyProperty, это не может быть сделано. Я мог бы показать вам несколько примеров, когда использование DependencyProperties действительно спасло день.

  4. Если все сделано правильно, создание свойства DependencyProperty в качестве источника данных на меньше кода (и проще), чем соответствующее свойство CLR, которое поддерживает INotifyPropertyChanged.

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

  6. Хранение для многочисленных свойств DependencyProperties * на 1039 * более эффективно , чем для многочисленных свойств CLR, что делает их отличными для объектов данных со многими значениями свойств 'null', 0, 'false' или 'Empty'.

  7. DependencyProperties обеспечивают превосходный потокобезопасный механизм , потому что они немедленно предупреждают вас, если вы пытаетесь использовать их ненадлежащим образом, а не молча делают неправильные вещи.

  8. Привязки могут автоматически и безопасно пересекать нити при необходимости, если вы привязываетесь к DependencyProperties. Если вы привязываетесь к свойствам CLR, защита вообще отсутствует, поэтому единственный безопасный способ - это заблокировать () код вашего объекта, если ваше приложение имеет несколько потоков. Невыполнение этого условия чревато опасностью из-за тонких проблем с многопоточностью, которые могут возникнуть при кэшировании, и правил упорядочения загрузки / хранения.

  9. DependencyProperties может эффективно поддерживать варьирование значений по умолчанию для типа объекта с помощью OverrideMetadata. Классические свойства CLR могут сделать это только путем запуска дополнительного кода каждый раз, когда объект создается.

Я мог бы продолжить и перечислить немало других веских причин для использования DependencyProperties в качестве источника ваших привязок, но я думаю, что вы поняли идею.

WPF был построен на основе предположения, что вы будете привязываться к DependencyProperties, а INotifyPropertyChanged был добавлен только позже (и неэффективно). Это свидетельствует о том, что группа очень хороших архитекторов программного обеспечения явно думала, что связывание DP -> DP было хорошим дизайном.

Я понимаю, что есть некоторые преимущества использования INotifyPropertyChanged вместо DP в определенных сценариях. Тем не менее, привязка DP -> DP, безусловно, не является «плохим дизайном», и во многих случаях это самый лучший дизайн.

2 голосов
/ 18 ноября 2009

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

public class MyClass : INotifyPropertyChanged
{
    public bool IsEverythingLoaded
    {
        get { return _isEverythingLoaded; }
        set
        {
            _isEverythingLoaded = value;
            OnPropertyChanged("IsEverythingLoaded");
        }
    }

    #region INotifyPropertyChanged implementation

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
       PropertyChangedEventHandler handler = PropertyChanged;
       if (handler != null)
           handler(this, new PropertyChangedEventArgs(propertyName));
    }

    #endregion
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...