Подтвердить что ты не робот

Демистификация свойств зависимостей

Я много читал о свойствах зависимостей на SO и других сайтах. Но, действительно, я не нашел отличного объяснения и до сих пор смущен. Я использую как SL, так и WPF. Различаются ли они в SL и WPF с точки зрения реализации? Почему они действительно нужны им? Статичны ли они, что их ценности разделены? Почему причиной MS были установлены свойства зависимостей?

Bounty: Я ищу более тщательный, полный ответ.

4b9b3361

Ответ 1

Ответ в самом имени, хотя слово "зависимость" настолько чревато смыслом в разработке программного обеспечения, что не особенно ясно, что это значит.

Свойство зависимости является свойством на одном объекте, значение которого зависит от какого-либо другого объекта. Так, например:

  • Значение свойства FontFamily объекта TextBox может (и обычно) зависит от свойства FontFamily его контейнера. Если вы измените свойство на контейнере, значение в TextBox изменится.

  • Значение свойства Text для TextBox может зависеть от связанного источника данных. Когда значение связанного свойства изменяется, изменяется значение свойства Text.

  • Значение свойства Opacity для Label может зависеть от раскадровки анимации, в общем сценарии, в котором вы настроили элемент пользовательского интерфейса, чтобы исчезать или исчезать в ответ на какое-либо событие.

  • Значение всех видов свойств для любого элемента пользовательского интерфейса может зависеть от стиля, который вы им применили.

Центральная концепция зависимости заключается в том, что вещь, которая зависит, должна получить значение свойства от вещи, в которой она зависит. Вот почему свойство зависимостей реализовано как свойство CLR, получатель которого вызывает метод.

Когда TextBox или вещь, которая его отображает, должна знать, что такое FontFamily, геттер FontFamily вызывает метод GetValue. Этот метод находит значение из контейнера или анимации, или привязки, или что-то еще.

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

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

Поскольку эта метаинформация одинакова для каждого объекта в классе (т.е. TextBox.Text работает одинаково для каждого TextBox), словарь, который он хранит, является статическим свойством класса.

Итак, когда вы видите такой код:

static Button()
{
   // Register the property
   Button.IsDefaultProperty = 
     DependencyProperty.Register("IsDefault",
     typeof(bool), typeof(Button),
     new FrameworkPropertyMetadata(false,
        new PropertyChangedCallback(OnIsDefaultChanged)));
}

что происходит, что метаинформация, которая определяет свойство IsDefault для всех объектов Button, добавляется к этому словарю. И когда вы видите это:

public bool IsDefault
{
  get { return (bool)GetValue(Button.IsDefaultProperty); }
  set { SetValue(Button.IsDefaultProperty, value); }
}

то, что вы видите, - это метод getter, который ищет значение свойства (из локального словаря, родительского объекта или любого другого) на основе этой метаинформации.

Помните, как я сказал, что первое место, которое геттер ищет, чтобы найти значение свойства, находится в локальном словаре объекта? Метод SetValue в установщике - это то, как эта запись добавляется в словарь (если она когда-либо была вызвана, что будет только тогда, когда вы переопределяете зависимость, явно устанавливая свойство, то есть говоря: "Я хочу, чтобы это TextBox для отображения текста в Consolas, независимо от того, что используют другие элементы управления в окне." ).

Чрезвычайно существенное преимущество, которое мы получаем от подобной, по-видимому, сложной системы, заключается в том, что свойства зависимостей на объектах потребляют только память, если они установлены. Если я создаю 10 000 TextBox элементов управления и добавлю их в Window, ни один из них не содержит ссылки на объект FontFamily. Это 10 000 ссылок на объекты, на которые я не выделяю память, и что сборщик мусора не проверяет. Фактически, если TextBox имеет 100 свойств зависимостей (и это примерно так), всякий раз, когда вы создаете TextBox, это 100 полей поддержки, для которых вы не выделяете память. Свойства зависимостей потребляют только память, если вы их явно задали. Поскольку подавляющее большинство объектов на объектах пользовательского интерфейса никогда не проявляются явно, это фантастическая экономия.

Ответ 2

Другие люди предоставили объяснения свойств зависимостей. Я постараюсь обеспечить некоторый контекст вокруг их дизайна. (Это помогло мне понять, почему эти причудливые творения называются свойствами зависимостей в первую очередь.) Было несколько причин, по которым дизайнеры WPF добавили свойства зависимостей, а не использовали обычные свойства...

  • Возможность добавления значения для свойства, которое не применимо к текущему элементу, но применимо к его дочерним элементам. Например, установка шрифта в контейнере и его каскадирование до любых содержащихся текстовых элементов.
  • Стоимость с точки зрения размера неиспользуемых свойств. Взяв пример шрифта выше... На хорошо продуманной странице только несколько элементов изменят свой шрифт - вероятно, несколько контейнеров верхнего уровня. Если мы сохранили Font в качестве обычного свойства С#, каждому объекту понадобился бы 32/64-битный указатель на объект шрифта с большинством из них null или со значением по умолчанию. Увеличьте это на количество свойств XAML и типичное количество элементов на странице, и в итоге вам потребуется огромное пространство для хранения ничего или значений по умолчанию. Сравните это с зависимыми свойствами, где значения занимают только пространство, если они установлены. (Я не смотрел на внутреннюю реализацию, но я предполагаю, что GetValue (propName) и SetValue (propName) сохраняют значения в какой-либо хэш-таблице для каждого объекта /per -propety.)

Было бы неплохо, если бы Microsoft предоставила хороший синтаксис для создания новых свойств зависимостей, спрятав повторяющийся код с помощью магии компилятора, как и для итераторов. Возможно, в С# 6...:)

Ответ 3

  • Разные ли они в SL и WPF?
    Нет

  • Почему мы действительно нуждаемся в них? Короткий ответ: мы нуждаемся в них для привязки и стилизации данных и почему они были добавлены MS.

  • Статичны ли они, что их ценности разделены?
    Статическая часть - это имя свойства, поэтому ее можно получить с помощью GetValue (propName) и установить с помощью SetValue (propName, value)

Ответ 4

Взгляните на Обзор свойств зависимостей на MSDN (или Версия Silverlight).

(Silverlight/WPF) предоставляет набор сервисов, которые могут использоваться для расширения функциональности свойства CLR. В совокупности эти службы обычно называются системой свойств (Silverlight/WPF). Свойство, которое поддерживается системой свойств (Silverlight/WPF), известно как свойство зависимостей.

Для отличий между системами свойств Silverlight и WPF см. здесь.

Пара причин, по которым система Property Dependency и подключение свойства с системой типа Silverlight/WPF важны, следующие: (здесь здесь для более подробных объяснений):

  • Позволяет настраивать свойство в стиле
  • Разрешает свойство поддерживать привязку данных
  • Позволяет анимировать свойство
  • Позволяет свойствам настраиваемого элемента управления получать поддержку дизайнера в Visual Studio

Обратите внимание, что свойство Dependency обычно поддерживается свойством CLR, что означает, что вы можете взаимодействовать с ним в коде так же, как и с свойством CLR.

Ответ 5

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

  • Различные поставщики для своей ценности, т.е. его значение может быть изменено во время выполнения различными поставщиками, такими как триггеры, стили, анимация, темы и т.д. (Приоритет значения свойства зависимостей)
  • Поддержка XAML (поддержка выражений).
  • Эффективная память (их статическая природа).
  • Изменить уведомления
  • Наследование свойств свойства (Прикрепленные свойства).

статьи, которые я нашел очень полезными -

Обзор свойств зависимостей в WPF: http://joshsmithonwpf.wordpress.com/2007/06/22/overview-of-dependency-properties-in-wpf/

Свойства внутренней зависимости: http://www.i-programmer.info/programming/wpf-workings/443-inside-dependency-properties-.html

WPF: статическая природа зависимости Свойства: http://dotnetslackers.com/Debugger/re-126399_WPF_The_Static_Nature_of_Dependency_Properties.aspx

Ответ 6

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

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

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

то есть. Вы удаляете настраиваемый элемент управления на поверхности в XAML и назначаете выражение привязки одному из своих свойств.

Я вижу, что некоторые люди используют их везде, думая, что они необходимы при разработке Silverlight/WPF, но это не так. У разных людей разные линии, которые они рисуют на песке, но я говорю, что они используют их только когда это необходимо, что почти 100% времени находится в пределах пользовательских элементов управления.

Самостоятельное продвижение Блантанта: у меня есть более глубокое (специальное предложение Silverlight) по этой теме в главе 10 моей книги Pro Business Applications в Silverlight 4.

Ответ 7

Чтобы добавить к тому, что уже было рассмотрено в других ответах:

Концептуально в их основных свойствах зависимости - это система, позволяющая запросить получение значения на основе списка разных источников, а не возврата одного сохраненного значения. Есть много последствий для этого, как указано во многих других ответах, но то, что на самом деле происходит, приводит к чему-то, что ведет себя таким образом при получении значения (естественно, упрощенно):

private string _coerced;
private string _animated;
private string _local;
private string _triggered;
private string _styled;
private string _inherited;
private string _default;

public string MyDP
{
    get
    {
        return _coerced ?? _animated ?? _local ?? _triggered ?? _styled ?? _inherited ?? _default;
    }
}