Свойства зависимостей в 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" /> 

он создаст текстовое поле пользовательского элемента управления, которое не позволит пространство. Таким образом, в основном свойство зависимостей позволяет добавлять функцию, расширять функцию любого элемента управления.