Как дизайн свойств зависимостей WPF экономит потребление памяти? - PullRequest
9 голосов
/ 21 августа 2011

Я прочитал это по следующей ссылке: -

HTTP: //www.informit.com/articles/article.aspx р = 688529 & SEQNUM = 2

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

Но, в конце концов, они где-то хранятся, как это экономит потребление памяти?

Ответы [ 2 ]

17 голосов
/ 21 августа 2011

См. Следующую ссылку: http://www.bobpowell.net/dependencyproperty.aspx

То, что объявляется объектом как свойство зависимости, фактически является не чем иным, как идентификатором.Это статическое «свойство» действительно является ключом, который связывает объект с определенным идентификатором хранилища.Например, графические объекты имеют свойство Background, которое можно установить явно или с помощью шаблонов или стилей.

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

Пример, обратите внимание, как Brushes.Black установлено в качестве значения по умолчанию

public static readonly DependencyProperty ForegroundProperty =
    DependencyProperty.Register(
        "Foreground",
        typeof(Brush),
        typeof(TextElement),
        new FrameworkPropertyMetadata(Brushes.Black, ...));

Подумайте об этом так: скажем, у вас есть четыре TextBlocks в Xaml

<StackPanel>
    <TextBlock .../>
    <TextBlock .../>
    <TextBlock .../>
    <TextBlock Foreground="Green" .../>
</StackPanel>

У трех TextBlocks в верхней части Foreground установлено Black хотя вы никогда не устанавливали явно 10 * черный .Они используют их значение по умолчанию.Таким образом, для свойства Foreground для трех TextBlocks, указанных выше, вам нужно только одно поле (так как оно является статическим).

Для четвертого TextBlock вы явно задали Foregroundзеленый, чтобы это значение было вставлено в словарь в качестве локального значения для Foreground в этом экземпляре и, таким образом, требует дополнительной памяти (также оно окажется на месте 3 в списке ниже, переопределяя Setters, Triggers и т. Д.) .

Кроме того, см. Следующий пост Джоша Смита, это хорошее чтение: Разоблачение свойств зависимостей

Тамэто четко определенный набор правил, который используется внутри WPF, чтобы выяснить, каково реальное значение DP.Вот краткое изложение правил приоритета, используемых при разрешении значения DP (подробнее об этом здесь ):

  1. Приведение системы свойств
  2. Активные анимации или анимации с поведением удержания
  3. Локальное значение
  4. Шаблон TemplatedParent
  5. Триггеры стиля
  6. Триггеры шаблона
  7. Установщики стилей
  8. Стиль темы
  9. Наследование
  10. Значение по умолчанию из метаданных свойства зависимостей

Редактировать: Ответить на комментарийfrom Duane

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

У обоих TextBlocks будет Foreground, установленный на Черный , но у последнего будет установлено локальное значение.Style сможет установить Foreground только для первого TextBlock, но не позднее, поскольку установщики стилей имеют более низкий приоритет, чем локальное значение.

<StackPanel>
    <StackPanel.Resources>
        <Style TargetType="TextBlock">
            <Setter Property="Foreground" Value="Green"/>
        </Style>
    </StackPanel.Resources>
    <TextBlock Text="Displays in Green"/>
    <TextBlock Foreground="Black" Text="Displays in Black"/>
</StackPanel>
5 голосов
/ 21 августа 2011

Сначала предположим, что вы создаете класс с дюжиной свойств.Создайте 100 000 из них.Сколько ссылок на объекты у вас сейчас есть?1 200 000.

Теперь реализуйте класс с именем DependencyObject:

public class DependencyObject
{
    public DependencyObject()
    {
       LocalValues = new Dictionary<string, object>();
    }

    protected Dictionary<string, object> LocalValues { get; set; }

    public DependencyObject Parent { get; set; }

    protected object GetValue(string propertyName)
    {
       if (LocalValues.ContainsKey(propertyName))
       {
          return LocalValues[propertyName];
       }
       return Parent.GetValue(propertyName);
    }

    protected void SetValue(string propertyName, object value)
    {
       LocalValues[propertyName] = value;
    }
}

Создайте производный класс следующим образом:

public class MyDependencyObject : DependencyObject
{
    public SomeType Property1
    {
       get { return (SomeType)GetValue("Property1"); }
       set { SetValue("Property1", value]; }
    }

    // create 11 more properties like this
}

Теперь создайте 100 000 экземпляров MyDependencyObjectи установите их Parent.Сколько ссылок на объекты используется (не считая родителя)?300 000.

Так наследование значений свойств работает в объектах зависимостей.

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