Свойства зависимостей в WPF
Я читал о свойствах зависимостей в нескольких книгах, но у всех есть одна общая черта, они просто говорят нам, как они реализованы (используя static readonly DependencyProperty
etc.), но не скажу точно, как они работают изнутри.
Я имею в виду, что они реализованы как статические, но по-прежнему применяется ко всем объектам.
Второй момент путаницы-присоединенные свойства.
есть ли учебник, который может объяснить все эти понятия в простой способ?
4 ответов
моя ментальная модель того, как работают свойства зависимости:
любой DependencyObject
класс реализует два специальных свойства. Одно, статическое свойство класса, является словарем DependencyProperty
объекты. Каждый экземпляр класса может заглянуть в этот словарь, чтобы найти метаинформацию о каждом DependencyProperty
- имя свойства, его тип, любые обратные вызовы, которые должны быть вызваны, когда он get и set, как он участвует в наследовании свойства и так далее. При регистрации зависимости собственность, вы добавляете запись в этот словарь.
другое свойство является свойством экземпляра: это словарь, ключом которого DependencyProperty
, который содержит local стоимостью каждого DependencyProperty
, если он был задан.
на SetValue
и GetValue
методы, которые вы реализуете в сеттере и геттере свойства CLR, в основном ленивая оценка на стероидах. Вместо того чтобы хранить и извлекать значение свойства в резервном поле, они хранят и получить значение свойства в словаре значений.
магия свойств зависимостей заключается в том, что GetValue
и SetValue
на самом деле делать.
GetValue
ищет значение свойства в словаре значений объекта. Если он не находит его, он вызывает GetValue
на родительском элементе, чтобы получить то, что родительский элемент считает значением. Например, при создании TextBox
на Window
, все, что смотрит на TextBox
' s FontFamily
на самом деле зову GetValue
. Если вы явно не установили шрифт, в его словаре нет записи для этого свойства. Так что GetValue
запрашивает значение у родительского элемента. Родительский элемент может иметь или не иметь FontFamily
установлен; если нет, то его вызов GetValue
возвращает значение его родитель. И так далее, пока Window
объект достигнут и фактический FontFamily
значение не найдено.
если вы устанавливаете FontFamily
на TextBox
, SetValue
сохраняет значение в словаре значений. Следующий все время должен получить значение FontFamily
для этого TextBox
, GetValue
находит значение в словаре и возвращает его, поэтому ему не нужно спрашивать родительский элемент.
если вы устанавливаете FontFamily
на Window
, SetValue
не только обновляет значение в Window
словарь значений, он запускает событие изменения свойства, которое слышит все, что зависит от свойства. (Вот почему они называются свойствами зависимостей, помните.) И если вещь, зависящая от свойства, сама является свойством зависимости, она запускает свои собственные события изменения свойств. Вот как это происходит, что изменение FontFamily
на Window
изменяет шрифт для каждого элемента управления в окне, а также предлагает WPF повторно отобразить измененные элементы управления.
свойства работы, используя такой же подход. Любой объект, который может иметь вложенные свойства, имеет словарь, в котором хранятся значения вложенных свойств. При установке Grid.Column
на CheckBox
в XAML вы просто добавляете запись в это CheckBox
's словарь. Когда Grid
необходимо знать, какой столбец CheckBox
находится в, он ищет значение из этого словаря. Когда вы установите Grid.IsSharedSizeScope
to True
на объекте словарь этого объекта будет содержать новое свойство-словарь, который содержит ширины / высоты для каждого SharedSizeKey
.
я должен подчеркнуть, что это моя ментальная модель. Я не сел с рефлектором и не посмотрел на фактический реализация Register
, GetValue
и SetValue
чтобы выяснить, как они на самом деле работают. Я могу ошибаться в деталях. Но это модель, которая точно предсказывает, как этот материал ведет себя, так что это достаточно хорошо.
концепция хранения значений свойств в словарях довольно странная для программистов C#. Это старая шляпа для программистов Python. В Python все свойства класса-фактически все объекты-хранятся в словарях, и поэтому вы можете получить к их стоимости либо через аксессоры свойств, либо просто просматривая их. Свойства зависимостей и прикрепленные свойства-это еще один способ, которым .NET, украв все, что было у Java, что стоило украсть, теперь грабит Python. (Или откуда питон их разграбил.) Изучение Python сделало меня гораздо лучшим программистом c#; я рекомендую его любому разработчику C#, который еще этого не сделал.
вот учебник по свойствам зависимостейhttp://www.wpftutorial.net/DependencyProperties.html это немного объясняет, как они работают.
краткое объяснение того, почему объект DependencyProperty находится в статическом поле, заключается в том, что он представляет описание свойства, а не значение свойства. Каждый DependencyObject имеет отображение объектов DependencyProperty на их значения.
Это также, как прикрепленные свойства работают. Поскольку каждый DependencyObject хранит отображение из любого DependencyProperty в значение, любой тип может создать новый DependencyProperty и установить его на любом существующем DependencyObject.
просто посмотрите этот пост от joshsmith, в нем есть дополнительная информация
http://joshsmithonwpf.wordpress.com/2007/06/22/overview-of-dependency-properties-in-wpf/
вы можете увидеть ниже очень простой пример dependency property
создает custom control text box
в котором пространство не будет разрешено означает, что пользователь не может ввести пространство в текстовое поле.
1) Создайте класс с именем ValidatedTextBox
и напишите следующий код в этом файле класса:
public class ValidatedTextBox : TextBox
{
public ValidatedTextBox()
{
}
public static readonly DependencyProperty IsSpaceAllowedProperty =
DependencyProperty.Register("IsSpaceAllowed", typeof(bool), typeof(ValidatedTextBox));
public bool IsSpaceAllowed
{
get { return (bool)base.GetValue(IsSpaceAllowedProperty); }
set { base.SetValue(IsSpaceAllowedProperty, value); }
}
protected override void OnPreviewKeyDown(KeyEventArgs e)
{
base.OnPreviewKeyDown(e);
if (!IsSpaceAllowed && (e.Key == Key.Space))
{
e.Handled = true;
}
}
}
2) Использовать выше контроля на ваш
a) добавить пространство имен текстового поля пользовательского элемента управления, как показано ниже:
xmlns:CustomControls="clr-namespace: ValidatedTextBox;assembly= ValidatedTextBox "
б), используй текстовом поле управления, как ниже:
<CustomControls:ValidatedTextBox IsSpaceAllowed="False" x:Name="MyTextBox" />
он создаст текстовое поле пользовательского элемента управления, которое не позволит пространство. Таким образом, в основном свойство зависимостей позволяет добавлять функцию, расширять функцию любого элемента управления.