WPF: Что отличает Свойство Зависимости от регулярного Свойства CLR?

В WPF, что, действительно, это означает быть "свойством зависимости"?

Я прочитал Обзор Свойств Зависимости Microsoft, но он действительно не впитывается для меня. Частично в той статье говорится:

Стили и шаблоны являются двумя из главных сценариев мотивации для использования свойств зависимости. Стили особенно полезны для установки свойств, которые определяют пользовательский интерфейс приложения (UI). Стили обычно определяются как ресурсы в XAML. Стили взаимодействуют с системой собственности, потому что они обычно содержат "методы set" для особых свойств, а также "триггеры", которые изменяют значение свойства на основе значения в реальном времени для другого свойства.

И затем пример кода - это:


....

Но я не получаю то, что является особенным об этом. Это просто подразумевает, это, когда я установил Style на кнопке к данному стилю, который я на самом деле устанавливаю Background неявно? Это - затруднение его?

6
задан Cheeso 24 February 2010 в 01:40
поделиться

3 ответа

Что в WPF означает "свойство зависимости"?

Чтобы быть свойством зависимости, свойство должно быть определено как DependencyProperty, статически, для класса. Система свойств зависимостей сильно отличается от стандартных свойств CLR.

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

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

Например, возьмем свойство зависимости DataContext. Обычно вы устанавливаете свойство DataContext зависимости для окна или UserControl. Все элементы управления внутри этого окна по умолчанию автоматически "наследуют" свойство DataContext своего родителя, что позволяет задавать привязки данных для элементов управления. При использовании стандартного свойства CLR вам пришлось бы определить этот DataContext для каждого элемента управления в окне, чтобы привязка работала правильно.

8
ответ дан 8 December 2019 в 02:12
поделиться

Может быть полезно понять, какую проблему пытается решить свойство зависимости.

Если мы отложим модели привязки, анимации и события изменения в сторону, как они обсуждались в других ответах, преимуществом будет использование памяти и, следовательно, масштабируемость для размещения многих тысяч объектов WPF в окне.

Если окно содержит 1000 объектов Label , каждый объект Label имеет обычный Foreground , Background , FontFamily , FontSize , FontWeight и т. Д., То обычно это потребляет память, потому что каждое свойство будет иметь частное резервное поле для хранения значения.

Большинство приложений изменят только несколько свойств, большинство из которых останутся со значениями по умолчанию. В основном очень расточительная и избыточная информация (каждый объект просто хранит в памяти одни и те же значения по умолчанию)

Вот где свойства зависимостей различаются.

// Lets register the Dependency Property with a default value of 20.5
public static readonly DependencyProperty ColumnWidthProperty =
    DependencyProperty.Register("ColumnWidth", typeof(double), typeof(MyWPFControl), new UIPropertyMetadata(20.5, ColWitdhPropChanged));

public double ColumnWidth
{
  get { return (double)GetValue(ColumnWidthProperty); }
  set { SetValue(ColumnWidthProperty, value); }
}

Нет частного резервного поля. Когда свойство зависимости зарегистрировано, можно указать значение по умолчанию. Таким образом, в большинстве случаев возвращаемое значение из GetValue является значением по умолчанию, которое было сохранено только один раз, чтобы охватить все экземпляры объекта Label во всех окнах вашего приложения.

Когда свойство зависимости устанавливается с помощью SetValue , оно сохраняет значение, отличное от значения по умолчанию, в коллекции, идентифицированной экземпляром объекта, для возврата во всех последующих вызовах GetValue .

Таким образом, этот метод хранения будет использовать память только для свойств объектов WPF, значение которых изменилось по сравнению со значением по умолчанию. т.е. только отличия от значения по умолчанию.

9
ответ дан 8 December 2019 в 02:12
поделиться

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

Свойства зависимостей - это значения, подобные свойствам, которые получаются и устанавливаются с помощью методов класса DependencyObject . Они могут (и обычно выглядят) очень похоже на свойства CLR, но это не так. И это первое, что их сбивает с толку. Свойство зависимости на самом деле состоит из нескольких компонентов.

Вот пример:

Документ является свойством объекта RichTextBox . Это настоящее свойство CLR. То есть у него есть имя, тип, получатель и сеттер, как и у любого другого свойства CLR. Но в отличие от «обычных» свойств, свойство RichTextBox не просто получает и устанавливает частное значение внутри экземпляра. Внутренне это реализовано следующим образом:

public FlowDocument Document
{
   get { return (FlowDocument)GetValue(DocumentProperty); }
   set { SetValue(DocumentProperty, value); }
}

Когда вы устанавливаете Document , переданное вами значение передается в SetValue вместе с DocumentProperty . А что то ? И как GetValue получает свое значение? И ... почему?

Во-первых, что. В RichTextBox определено статическое свойство с именем DocumentProperty .Когда это свойство объявляется, это делается следующим образом:

public static DependencyProperty DocumentProperty = DependencyProperty.Register(
    "Document",
    typeof(FlowDocument), 
    typeof(RichTextBox));

В данном случае метод Register сообщает системе свойств зависимостей, что RichTextBox - тип, а не экземпляр - теперь имеет свойство зависимости с именем Документ типа FlowDocument . Этот метод хранит эту информацию ... где-нибудь. Где именно находится скрытая от нас деталь реализации.

Когда установщик для свойства Document вызывает SetValue , метод SetValue просматривает аргумент DocumentProperty , проверяет, действительно ли он свойство, которое принадлежит RichTextBox и что значение является правильным типом, а затем сохраняет свое новое значение ... где-то. В документации для DependencyObject эта деталь реализации скромна, потому что вам действительно не нужно ее знать. В моей мысленной модели того, как это работает, я предполагаю, что есть свойство типа Dictionary , которое является частным для DependencyObject , поэтому производные классы (например, RichTextBox ) не может его видеть, но GetValue и SetValue могут его обновить. Но кто знает, может, это написано на пергаменте монахами.

В любом случае, это значение теперь называется «локальным значением», то есть это значение, которое является локальным для этого конкретного RichTextBox , как и обычное свойство.

Суть всего в следующем:

  1. Коду CLR не нужно знать, что свойство является свойством зависимости.Выглядит точно так же, как и любой другой объект недвижимости. Вы можете вызвать GetValue и SetValue , чтобы получить и установить его, но если вы не делаете что-то с системой свойств зависимостей, вам, вероятно, не нужно .
  2. В отличие от обычного свойства, в его получении и настройке может быть задействовано нечто иное, чем объект, которому оно принадлежит. (Возможно, вы могли бы сделать это с помощью отражения, но отражение происходит медленно. Поиск в словарях выполняется быстро.)
  3. Это нечто - то есть система свойств зависимостей - по существу находится между объектом и его свойствами зависимостей. И он может делать все .

Что за вещи? Что ж, давайте рассмотрим несколько вариантов использования.

Переплет. Когда вы привязываетесь к свойству, это должно быть свойство зависимости. Это связано с тем, что объект Binding на самом деле не устанавливает свойства целевого объекта, он вызывает SetValue целевого объекта.

Стили. Когда вы устанавливаете свойство зависимостей объекта на новое значение, SetValue сообщает системе стилей, что вы это сделали. Вот как работают триггеры: они не обнаруживают, что значение свойства изменилось с помощью магии, сообщает им система свойств зависимостей.

Динамические ресурсы. Если вы напишете XAML как Background = {DynamicResource MyBackground} , вы можете изменить значение ресурса MyBackground , и фон объекта, на который он ссылается, будет обновлен. Это тоже не волшебство; динамический ресурс вызывает SetValue .

Анимация. Анимация работает, управляя значениями свойств. Это должны быть свойства зависимости, потому что анимация вызывает SetValue , чтобы добраться до них.

Уведомление об изменении. Когда вы регистрируете свойство зависимости, вы также можете указать функцию, которую SetValue будет вызывать при установке значения свойства.

Наследование ценностей. Когда вы регистрируете свойство зависимости, вы можете указать, что оно участвует в наследовании значения свойства. Когда вы вызываете GetValue , чтобы получить значение свойства зависимости объекта, GetValue проверяет, есть ли локальное значение. Если нет, он проходит вверх по цепочке родительских объектов, просматривая их локальные значения для этого свойства.

Вот как вы можете установить FontFamily в Window и волшебным образом (я часто использую это слово) каждый элемент управления в окне использует новый шрифт . Кроме того, вы можете иметь сотни элементов управления в окне, при этом каждый из них не имеет переменной-члена FontFamily для отслеживания своего шрифта (поскольку у них нет локальных значений), но вы все равно можете установить FontFamily на любом элементе управления (из-за скрытого словаря значений seekrit, который есть у каждого DependencyObject ).

27
ответ дан 8 December 2019 в 02:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: