Dependency Properties
От: stalcer Россия  
Дата: 02.08.11 13:45
Оценка:
Здравствуйте,

Никак не пойму вот что: Механизм Dependency Properties вроде бы не зависит от WPF. Т.е. наоборот WPF строится на основе Dependency Properties. Т.е. получается что я могу этот механизм использовать в своей иерархии классов, предположим — совсем не относящихся к UI. Нужно только отнаследовать мои классы от DependencyObject. Правильно?

Вопрос: Как в этом случае указать по какой цепочке нужно искать значение свойства? Ну вот в WPF значение ищется локально, потом в стиле, потом в паренте, ну и т.п (это я упрощенно и, наверное, не совсем верно написал). Как мне свою цепочку задать для моих классов? Что то не вижу подходящего API в DependencyObject...
Re: Dependency Properties
От: Хэлкар  
Дата: 02.08.11 15:45
Оценка:
S>Никак не пойму вот что: Механизм Dependency Properties вроде бы не зависит от WPF. Т.е. наоборот WPF строится на основе Dependency Properties. Т.е. получается что я могу этот механизм использовать в своей иерархии классов, предположим — совсем не относящихся к UI. Нужно только отнаследовать мои классы от DependencyObject. Правильно?

Правильно.

S>Вопрос: Как в этом случае указать по какой цепочке нужно искать значение свойства? Ну вот в WPF значение ищется локально, потом в стиле, потом в паренте, ну и т.п (это я упрощенно и, наверное, не совсем верно написал). Как мне свою цепочку задать для моих классов? Что то не вижу подходящего API в DependencyObject...


AFAIK стандартного нет.
Re[2]: Dependency Properties
От: stalcer Россия  
Дата: 02.08.11 15:59
Оценка:
Здравствуйте, Хэлкар, Вы писали:

Х>AFAIK стандартного нет.


Дык, я вообще не понимаю, как сделать это хоть каким-нибудь способом. Ведь при поиске значения свойства, система пробегает по объектам сама, не спрашивая меня. Откуда ж она знает по каким объектам пробегать? Вроде кажется, что стандартного способа не быть просто не может. Может он просто недоступный? Ведь как-то сам WPF то они реализовали.
Re[3]: Dependency Properties
От: Codechanger Россия  
Дата: 02.08.11 16:19
Оценка:
Здравствуйте, stalcer, Вы писали:

S>Здравствуйте, Хэлкар, Вы писали:


Х>>AFAIK стандартного нет.


S>Дык, я вообще не понимаю, как сделать это хоть каким-нибудь способом. Ведь при поиске значения свойства, система пробегает по объектам сама, не спрашивая меня. Откуда ж она знает по каким объектам пробегать? Вроде кажется, что стандартного способа не быть просто не может. Может он просто недоступный? Ведь как-то сам WPF то они реализовали.



Система не пробегает по дереву объектов.Почитайте про то, как эти свойства хранятся, и многое станет ясным. Вообще сама концепция DependencyProperty была введена, чтобы уменьшить количество потребляемой памяти из-за дикого количества свойств у объектов WPF. Если каждому объекту в дереве еще и задавать все свойства, то настанет OutOfMemory достаточно скоро. Да и поиск будет совсем неэффективен.
Re[4]: Dependency Properties
От: MxMsk Португалия  
Дата: 02.08.11 16:30
Оценка:
Здравствуйте, Codechanger, Вы писали:

C>Система не пробегает по дереву объектов.Почитайте про то, как эти свойства хранятся, и многое станет ясным. Вообще сама концепция DependencyProperty была введена, чтобы уменьшить количество потребляемой памяти из-за дикого количества свойств у объектов WPF. Если каждому объекту в дереве еще и задавать все свойства, то настанет OutOfMemory достаточно скоро. Да и поиск будет совсем неэффективен.

Не-не-не. Цель Dependency Property главным образом вытекает из названия, а именно — зависимость значения свойства от окружения (зачастую, положения в визуальном дереве). Экономить память научились еще в Windows Forms, но никаких Dependency Property там нет.
Re: Dependency Properties
От: MxMsk Португалия  
Дата: 02.08.11 16:55
Оценка:
Здравствуйте, stalcer, Вы писали:

S>Вопрос: Как в этом случае указать по какой цепочке нужно искать значение свойства? Ну вот в WPF значение ищется локально, потом в стиле, потом в паренте, ну и т.п (это я упрощенно и, наверное, не совсем верно написал). Как мне свою цепочку задать для моих классов? Что то не вижу подходящего API в DependencyObject...

Ты несколько неправильно понял. Да, можно сказать, что значение "ищется", но на самом деле это не так. Рассмотрим твои примеры. Локальное значение — это значение, лежащее прямо в свойстве. Здесь никакого поиска и не нужно. Далее, значение из стиля. Когда WPF применяет к элементу стиль, тогда оно копирует значение из стиля в свойство. Просто оно ставит в свойстве флажок, говорящий о том, что значение взято из стиля, а значит, если появится локальное значение, оно должно "затереть" значение из стиля. Что еще? Наследование значения. И снова нет никакого поиска, т.к. такое значение идет "сверху-вниз", то бишь, от родителя к дочернему элементу, а не наоборот. И главное, DependencyObject, о котором мы говорим — все-таки механизм ориентированный на WPF. Об этом говорит хотя-бы тот факт, что есть еще WCF, где тоже есть свой собственный DependencyObject.
Re[4]: Dependency Properties
От: Аноним  
Дата: 02.08.11 18:24
Оценка:
Здравствуйте, Codechanger, Вы писали:

C>Система не пробегает по дереву объектов.Почитайте про то, как эти свойства хранятся, и многое станет ясным. Вообще сама концепция DependencyProperty была введена, чтобы уменьшить количество потребляемой памяти из-за дикого количества свойств у объектов WPF. Если каждому объекту в дереве еще и задавать все свойства, то настанет OutOfMemory достаточно скоро. Да и поиск будет совсем неэффективен.


Да понимаю я как они хранятся. Я не понимаю как указать для MyTransaction что если значение не локальное, то оно должно браться из Session? Т.е. откуда функция GetValue, вызываемая из MyTransaction.Isolation.get вообще узнает про Session?

public class MyTransaction: DependencyObject
{
    public int Isolation
    {
        get { return (int)GetValue(IsolationProperty); }
        set.....
    }

    public MySession Session
    {
        get....
        set....
    }
}

public class MySession: DependencyObject
{
    public int Isolation
    {
        get { return (int)GetValue(MyClass.IsolationProperty); }
    }
}
Re[5]: Dependency Properties
От: stalcer Россия  
Дата: 02.08.11 18:25
Оценка:
Блин, анонимно отправилось...
Re[2]: Dependency Properties
От: stalcer Россия  
Дата: 02.08.11 18:34
Оценка:
Здравствуйте, MxMsk, Вы писали:

MM>Ты несколько неправильно понял. Да, можно сказать, что значение "ищется", но на самом деле это не так.


Понятное дело. Я имел ввиду "логически" ищется. А как уж оно там оптимизировано — это другой вопрос.
Ответь тогда вот на это: http://www.rsdn.ru/forum/dotnet.gui/4365661.1.aspx
Автор:
Дата: 02.08.11

Вообще возможно это сделать?
Re[5]: Dependency Properties
От: MxMsk Португалия  
Дата: 02.08.11 18:34
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Да понимаю я как они хранятся. Я не понимаю как указать для MyTransaction что если значение не локальное, то оно должно браться из Session? Т.е. откуда функция GetValue, вызываемая из MyTransaction.Isolation.get вообще узнает про Session?

Для такого есть CoerceValueCallback. Пишешь его для IsolationProperty, проверяя внутри наличие локального значения при помощи GetValueSource. И не забудь добавить обработчик изменения свойства Session, который будет вызываеть CoerceValue для IsolationProperty.
Re[6]: Dependency Properties
От: stalcer Россия  
Дата: 02.08.11 18:54
Оценка:
Здравствуйте, MxMsk, Вы писали:

MM>Для такого есть CoerceValueCallback. Пишешь его для IsolationProperty, проверяя внутри наличие локального значения при помощи GetValueSource.


Че-то ты путаешь, имхо. CoerceValueCallback — вааще не для этого.
Вот, кстати GetValueSource. Возвращает System.Windows.ValueSource в котором есть BaseValueSource. Очень интересный енум:

    public enum BaseValueSource
    {
        Unknown = 0,
        Default = 1,
        Inherited = 2,
        DefaultStyle = 3,
        DefaultStyleTrigger = 4,
        Style = 5,
        TemplateTrigger = 6,
        StyleTrigger = 7,
        ImplicitStyleReference = 8,
        ParentTemplate = 9,
        ParentTemplateTrigger = 10,
        Local = 11
    }


Что означает, что DependencyObject нифига не независимая технология. И все это просто вшито в WPF. Тогды понятно, вопрос снят.
Re[7]: Dependency Properties
От: MxMsk Португалия  
Дата: 02.08.11 19:19
Оценка: +1
Здравствуйте, stalcer, Вы писали:

MM>>Для такого есть CoerceValueCallback. Пишешь его для IsolationProperty, проверяя внутри наличие локального значения при помощи GetValueSource.

S>Че-то ты путаешь, имхо. CoerceValueCallback — вааще не для этого.
В-общем случае, это метод корректировки значения. Он здесь вполне подойдет.

S>Вот, кстати GetValueSource. Возвращает System.Windows.ValueSource в котором есть BaseValueSource. Очень интересный енум:

S>Что означает, что DependencyObject нифига не независимая технология. И все это просто вшито в WPF. Тогды понятно, вопрос снят.
Рановато ты вопрос снял, не разобравшись. Да, DependencyObject не независимая технология. Его, кстати, никто никогда таким и не позиционировал. Тем не менее, он отделен от визуального слоя, потому что лежит в сборке WindowsBase. Тип BaseValueSource лежит в PresentationFramework, которая суть конечный код реализации WPF. Поэтому явно DependencyObject на WPF не завязан, но предназначен для нее. DependencyObject отлично подходит для случаев, где нужно использовать Dependency Property. Твой пример отчасти таков (пишу "отчасти", т.к. мы не знаем всех подробностей). В нем значение свойства зависит от нескольких источников, от локального значения и от сессии.
Re[8]: Dependency Properties
От: stalcer Россия  
Дата: 03.08.11 06:25
Оценка:
Здравствуйте, MxMsk, Вы писали:

MM>Рановато ты вопрос снял, не разобравшись. Да, DependencyObject не независимая технология. Его, кстати, никто никогда таким и не позиционировал. Тем не менее, он отделен от визуального слоя, потому что лежит в сборке WindowsBase. Тип BaseValueSource лежит в PresentationFramework, которая суть конечный код реализации WPF.


Ну да. Вижу. DependencyPropertyHelper.GetValueSource. На Helper то я внимания и не обратил. Тогда уже лучше...

MM>Поэтому явно DependencyObject на WPF не завязан, но предназначен для нее. DependencyObject отлично подходит для случаев, где нужно использовать Dependency Property. Твой пример отчасти таков (пишу "отчасти", т.к. мы не знаем всех подробностей).


Дык и я не знаю. Это ж просто пример .

Я думаю что сам WPF не использует CoerceValueCallback для организации цепочек (объект-стиль-парент-...). Тогда как он сам то сделан?
Re[9]: Dependency Properties
От: MxMsk Португалия  
Дата: 03.08.11 08:04
Оценка:
Здравствуйте, stalcer, Вы писали:

S>Я думаю что сам WPF не использует CoerceValueCallback для организации цепочек (объект-стиль-парент-...). Тогда как он сам то сделан?

На пальцах я уже объяснял
Автор: MxMsk
Дата: 02.08.11
. Есть приоритет значений и есть моменты, когда те или иные значения присваиваются. Это только выглядит, как цепочка поиска, а на самом деле, это скорее "приоритет присваивания".
Re[10]: Dependency Properties
От: stalcer Россия  
Дата: 03.08.11 08:36
Оценка:
Здравствуйте, MxMsk, Вы писали:

MM>На пальцах я уже объяснял
Автор: MxMsk
Дата: 02.08.11
. Есть приоритет значений и есть моменты, когда те или иные значения присваиваются. Это только выглядит, как цепочка поиска, а на самом деле, это скорее "приоритет присваивания".


Вопросов три:
1) Откуда такая инфа? Можешь дать ссылку, где почитать?
2) Можешь, если не лень, в мой пример вписать код, чтобы получилось так как это делает WPF. А то не совсем понятно...
3) Да и потом. Как-то странно получается: если это "приоритет присваивания", как ты пишешь, то какая же тогда экономия памяти — это значит что в каждом объекте для каждого свойства есть место под значение, да еще и с флагами. Ну, то есть, если один стиль применяется к 100-а объектам, то по твоей логике получается, что значение свойств из этого стиля копируется во все 100 объектов.
Re[11]: Dependency Properties
От: MxMsk Португалия  
Дата: 03.08.11 11:26
Оценка:
Здравствуйте, stalcer, Вы писали:

S>Вопросов три:

S>1) Откуда такая инфа? Можешь дать ссылку, где почитать?
Инфа личная, полученная из чтения исходников WPF через Reflector и ILSpy. Возможно эта ссылка будет полезна.

S>2) Можешь, если не лень, в мой пример вписать код, чтобы получилось так как это делает WPF. А то не совсем понятно...

Под рукой Студии нет, так что условно:
public class MyTransaction: DependencyObject
{
    public static readonly IsolationProperty = DependencyProperty.Register(...,
        new FrameworkPropertyMetadata(..., new CoerceValueCallback(CoerceIsolationProperty)));

    private static object CoerceIsolationProperty(DependencyObject d, object baseValue)
    {
        if (DependencyPropertyHelper.GetValueSource(d, IsolationProperty).BaseValueSource != BaseValueSource.Local
            &&
            Session != null)
        {
            return Session.Isolation;
        }

        return baseValue;
    }

    public int Isolation
    {
        get { return (int)GetValue(IsolationProperty); }
        set.....
    }

    public MySession Session
    {
        get....
        set
        {
            ....
            CoerceValue(IsolationProperty);
        }
    }
}

Если Session тоже Dependency Property, то CoerceValue надо перенести в обработчик OnPropertyChanged, который следует указать при регистрации свойства, аналогично CoerceIsolationProperty.

S>3) Да и потом. Как-то странно получается: если это "приоритет присваивания", как ты пишешь, то какая же тогда экономия памяти — это значит что в каждом объекте для каждого свойства есть место под значение, да еще и с флагами. Ну, то есть, если один стиль применяется к 100-а объектам, то по твоей логике получается, что значение свойств из этого стиля копируется во все 100 объектов.

Все значения свойств хранятся в виде object. Поэтому копируется только ссылка. В случае незамораживаемых Freezable-ов в некоторых случаях делается полное копирование, но в такие дебри влезать не охота
Re[12]: Dependency Properties
От: stalcer Россия  
Дата: 03.08.11 18:25
Оценка:
Здравствуйте, MxMsk, Вы писали:

MM>Инфа личная, полученная из чтения исходников WPF через Reflector и ILSpy. Возможно эта ссылка будет полезна.


Статья ничего по сути вопроса не объясняет, к сожалению.

MM>Под рукой Студии нет, так что условно:


Через CoerceValueCallback я понял... Я имел ввиду написать так, как в WPF это сделано. Т.е. не через CoerceValueCallback.

MM>Все значения свойств хранятся в виде object. Поэтому копируется только ссылка. В случае незамораживаемых Freezable-ов в некоторых случаях делается полное копирование, но в такие дебри влезать не охота


Имхо в 90% случаев ссылка (т.е. указатель) по размеру больше или равно размеру значения (Color, Width, Height, IsPressed и т.п.). Честно говоря, я все таки думаю, что физический поиск все-таки есть. Т.е. значения хранятся в какой-нибудь хэш-таблице, и даже для того, чтобы проверить установлено ли локальное значение нужно искать в этой таблице по составному ключу — (объект + DP).

Не говоря уже о цепочках (стили, паренты). Хотя я допускаю, что как раз цепочки делаются "присвоением", как ты говоришь. Тогда экономия памяти работает только на том, утановлено ли вообще значение или нет. Ну т.е. если значение установлено, то оно хранится в хэш-таблице, как описано выше. А если не установлено — то берется дефолтное из PropertyMetadata. Таким образом на дефолтные значения для каждого объекта память не тратится.

Другими словами, я могу поверить в то что: сам DependencyObject поддерживает только два уровня:
— дефолтное значение, хранящееся в PropertyMetadata (один раз для всех объектов)
— и локальное значение, хранящееся для каждого объекта отдельно только в том случае, если оно установлено.
Re[13]: Dependency Properties
От: MxMsk Португалия  
Дата: 03.08.11 18:58
Оценка:
Здравствуйте, stalcer, Вы писали:

MM>>Под рукой Студии нет, так что условно:

S>Через CoerceValueCallback я понял... Я имел ввиду написать так, как в WPF это сделано. Т.е. не через CoerceValueCallback.
Гм. Я что-то перестаю понимать. Что означает "как сделано в WPF"? В WPF это вообще никак не сделано. Это же ортогональные вещи: базовая реализация свойств и ее использование.

MM>>Все значения свойств хранятся в виде object. Поэтому копируется только ссылка. В случае незамораживаемых Freezable-ов в некоторых случаях делается полное копирование, но в такие дебри влезать не охота

S>Имхо в 90% случаев ссылка (т.е. указатель) по размеру больше или равно размеру значения (Color, Width, Height, IsPressed и т.п.). Честно говоря, я все таки думаю, что физический поиск все-таки есть. Т.е. значения хранятся в какой-нибудь хэш-таблице, и даже для того, чтобы проверить установлено ли локальное значение нужно искать в этой таблице по составному ключу — (объект + DP).
Конечно, свойства хранятся внутри хэш-таблицы, но мы вроде не об этом. С размером тоже не могу согласиться. Как-правило, 50% свойств — это ссылки на другие объекты или структуры, более сложные нежели элементарные типы.

S>Не говоря уже о цепочках (стили, паренты). Хотя я допускаю, что как раз цепочки делаются "присвоением", как ты говоришь. Тогда экономия памяти работает только на том, утановлено ли вообще значение или нет. Ну т.е. если значение установлено, то оно хранится в хэш-таблице, как описано выше. А если не установлено — то берется дефолтное из PropertyMetadata. Таким образом на дефолтные значения для каждого объекта память не тратится.

S>Другими словами, я могу поверить в то что: сам DependencyObject поддерживает только два уровня:
S>- дефолтное значение, хранящееся в PropertyMetadata (один раз для всех объектов)
S>- и локальное значение, хранящееся для каждого объекта отдельно только в том случае, если оно установлено.
Примерно так и есть: либо дефолтное в метаданных, либо отдельное значение в паре с приоритетом. В пользу такой реализации говорит и наличие метода ClearValue. Почему вообще всплыла эта тема с экономией памяти? Dependency Property придумали не для экономии, а как некоторый селектор эффективного значения из разных источников.
Re[14]: Dependency Properties
От: MxMsk Португалия  
Дата: 03.08.11 19:20
Оценка:
Здравствуйте, MxMsk, Вы писали:

S>>Другими словами, я могу поверить в то что: сам DependencyObject поддерживает только два уровня:

S>>- дефолтное значение, хранящееся в PropertyMetadata (один раз для всех объектов)
S>>- и локальное значение, хранящееся для каждого объекта отдельно только в том случае, если оно установлено.
MM>Примерно так и есть: либо дефолтное в метаданных, либо отдельное значение в паре с приоритетом.
Надо добавить, что есть еще один уровень: выражения. Реализация выражений — это BindingExpression и DynamicResourceExpression, которые обеспечивают работу привязки данных и динамических ссылок на ресурсы соответственно. В сущности, выражения используются как расширения источников значений для Dependency Property. Значения выражений при этом всё-равно кладутся по месту.
Re[14]: Dependency Properties
От: stalcer Россия  
Дата: 04.08.11 14:03
Оценка:
Здравствуйте, MxMsk, Вы писали:

MM>Гм. Я что-то перестаю понимать. Что означает "как сделано в WPF"? В WPF это вообще никак не сделано. Это же ортогональные вещи: базовая реализация свойств и ее использование.


Ну вот в WPF, я беру и спокойно наследюсь от какого-нибудь стандартного класса, например от Control. Добавляю туда новое DP. И оно у меня автоматически будет работать также как все остальные WPF свойства, т.е. значение будет подтягиваться из стиля, если оно там есть, и потом из парента и т.д. Мне же не нужно для этого в самом этом свойстве делать всякие CoerceValueCallback.

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

MM>Примерно так и есть: либо дефолтное в метаданных, либо отдельное значение в паре с приоритетом. В пользу такой реализации говорит и наличие метода ClearValue.


Ну, то что хэш таблица там есть — это понятно. Я просто думал что она используется немного по другому. Типа ищем локальное значение по ключу (Control+DP); если не находится — ищем по ключу (Control.Style+DP), если не находится... ну и т.п. Ну и потом если ниче не нашлось, тогда берем default из метаданных. Тогда вот получается реальная экономия памяти.

MM>Почему вообще всплыла эта тема с экономией памяти?


Дык так везде написано, в том числе и в их же доках. Я понимаю, что это не единственное для чего их придумали.

MM>Dependency Property придумали не для экономии, а как некоторый селектор эффективного значения из разных источников.


Вот тут меня и клинит. Потому что, если это "некоторый селектор эффективного значения из разных источников", то почему же в DependencyObject нет методов с помощью которых можно было бы указать эти "разные источники" для данного объекта.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.