Comments 43
Спасибо, очень интересное решение, как минимум в плане отсутствия написания одинакового кода. Правда к подобным ухищрение приводит печальное отсутствие макросов образца Nemerle.
+3
Mono. Fuck yea.
-2
Здорово, но атрибут лучше переименовать во что-нибудь более адекватное, например: NotifyOnChanged.
+4
Не первый раз слышу такое предложение, для этого даже параметризировал названия атрибутов в .targets файле.
0
Попутный вопрос.
Я немного далек от INPC, но RaisePropertyChanged — это устоявшаяся форма вызова события? Или все-таки по гайдлайнам virtual protected метод для вызова события должен наименоваться OnPropertyChanged и уже иметь в качестве аргумента PropertyChangedEventArgs?
Я немного далек от INPC, но RaisePropertyChanged — это устоявшаяся форма вызова события? Или все-таки по гайдлайнам virtual protected метод для вызова события должен наименоваться OnPropertyChanged и уже иметь в качестве аргумента PropertyChangedEventArgs?
0
Raise обычно. и логично. On- как раз для virtual методов и это уже совсем другой подход, основанный не на делегатах, а на перегрузке. привык искать Raise-, но иногда попадаются On-
видимо, по инерции бывших VB-кодеров
видимо, по инерции бывших VB-кодеров
+1
В идеале — сделать поддержку сразу нескольких «стилей»: RaisePropertyChanged, OnPropertyChanged, NotifyPropertyChanged, InvokePropertyChanged.
+1
и еще, HeyPropertyToUzheChanged ))
+3
Нашел интересную ссылку ровно по этому поводу.
Видимо, случай похожий на ID. Но по гайдам на мсдн все-таки OnEventName.
Видимо, случай похожий на ID. Но по гайдам на мсдн все-таки OnEventName.
+3
Этот метод является небольшим исключением.
Во-первых, он не совсем обязательно должен быть protected.
Во-вторых, если параметром будет PropertyChangedEventArgs — это просто праздник какой-то в каждом сеттере его создавать :)
Во-первых, он не совсем обязательно должен быть protected.
Во-вторых, если параметром будет PropertyChangedEventArgs — это просто праздник какой-то в каждом сеттере его создавать :)
0
RaiseEventName — для открытых методов, вызывающих событие. OnEventName — для защищённых методов, возможно предназначенных для переопределения в наследниках.
Само название метода RaiseEventName говорит о том, что он предназначен для вызова извне.
Само название метода RaiseEventName говорит о том, что он предназначен для вызова извне.
+1
Есть еще вариант с работой через прокси объект.
Пробовал такой механизм на NHibernate, где и так прокси генерится (для lazy), поэтому лишнего расхода нет.
При этом достаточно свойства сущностей объявлять как virtual, а в генераторе прокси написать единообразную обработку вызова сеттеров.
Ну а про MVVM — все-таки там не только нотификация изменений. Да и этот уровень, он ведь ViewModel, модель представления, он не должен быть тяжеловесным, да и производительность не так критична, т.к. «тормозом» обычно является пользователь.
Пробовал такой механизм на NHibernate, где и так прокси генерится (для lazy), поэтому лишнего расхода нет.
При этом достаточно свойства сущностей объявлять как virtual, а в генераторе прокси написать единообразную обработку вызова сеттеров.
Ну а про MVVM — все-таки там не только нотификация изменений. Да и этот уровень, он ведь ViewModel, модель представления, он не должен быть тяжеловесным, да и производительность не так критична, т.к. «тормозом» обычно является пользователь.
0
Давно уже ни для кого не секрет, что DependencyProperty тормознее ручной реализации INPC.
Ну и установка значения прям в field будет, наверное, быстрее, чем в property. Но нам это не так интересно. Скорее всего нужно думать в случае WPF и Silverlight об установке значений в свойства, а так же о времени Binding, то есть передачи значения самому контролу, а вот тут вот ситуация меняется в другую сторону. Не даром вы говорите о множестве полей у объекта, а так же о множествах ViewModel привязанных к DataGrid.
По WPF есть набор статей связанных с оптимизацией на MSDN, вот одна из них касательно вашей темы Optimizing Performance: Data Binding. И там как раз DP работает шустрее CLR объекта с INotifyPropertyChanged. Но ненамного, то есть это не есть место для оптимизации. В Silverlight, думаю, все должно быть примерно так же.
Собственно, часть статьи про оптимизацию считаю неоправданной: не там и не то оптимизировали. А по поводу AOP — это бесспорно хороший вариант. Есть еще более простой вариант — написать свой сниппет в VS. Типа такого C# Code Snippets for properties raising PropertyChanged event.
+5
Сниппеты не рефакториабельны без Решарпера, плюс ко всему — очень много букаф ;)
Но согласен, до KindOfMagic моим ежедневным решением были именно сниппеты.
Насчет, производительности data-binding — msdn-статье доверяй, но проверяй. У меня dependencyObjects ну никак быстрее не получаются, чем обычные свойства.
И этому есть объктивные причины:
1) прямой доступ без Dictionary
2) родная проверка на изменение
В чем могут dependency properties выигрывать — так это в боксинге. Происходит один раз в сеттере и геттере, а так везде как Object передается и хранится.
Но согласен, до KindOfMagic моим ежедневным решением были именно сниппеты.
Насчет, производительности data-binding — msdn-статье доверяй, но проверяй. У меня dependencyObjects ну никак быстрее не получаются, чем обычные свойства.
И этому есть объктивные причины:
1) прямой доступ без Dictionary
2) родная проверка на изменение
В чем могут dependency properties выигрывать — так это в боксинге. Происходит один раз в сеттере и геттере, а так везде как Object передается и хранится.
0
На сколько я понимаю вы тестируете просто тупо установку значений в свойства, так? Тут очевидно, что DP должен проигрывать. А вот в статье говорится о времени байдинга, как раз то, что нам очень важно в SL/WPF.
То есть верным тестом было бы создание для каждого свойства байдинга к какому-нибудь объекту и уже потом установка свойств, и подсчет времени.
То есть верным тестом было бы создание для каждого свойства байдинга к какому-нибудь объекту и уже потом установка свойств, и подсчет времени.
0
Байдинг от слова байда или байдарка? ;)
Да, в тест-проекте тестируется только запись свойства и перезапись с другим значением. Это нужно для того, чтобы выпятить на поверхность тот функционал, производительность которого я и хочу сравнивать.
Мой комментарий по поводу производительности дата-байндинга относился именно к впечатлению вцелом.
Давайте не будем забывать, что dependency properties это костыль, придуманный MS исключительно ради Attached properties, типо Grid.Column.
Остальное их испотзование притянуто за уши, т.к. Xaml замечательно работает и с простыми свойствами.
Да, в тест-проекте тестируется только запись свойства и перезапись с другим значением. Это нужно для того, чтобы выпятить на поверхность тот функционал, производительность которого я и хочу сравнивать.
Мой комментарий по поводу производительности дата-байндинга относился именно к впечатлению вцелом.
Давайте не будем забывать, что dependency properties это костыль, придуманный MS исключительно ради Attached properties, типо Grid.Column.
Остальное их испотзование притянуто за уши, т.к. Xaml замечательно работает и с простыми свойствами.
0
Байдинг от слова байда или байдарка? ;)
Байдинг — так оно произносится, одно время тоже делали мне замечания по поводу «биндинг».
Да, в тест-проекте тестируется только запись свойства и перезапись с другим значением. Это нужно для того, чтобы выпятить на поверхность тот функционал, производительность которого я и хочу сравнивать.
В итоге вы не сравнили ничего, точнее сравнили, но впустую. DependencyObject нужно использовать только в контексте с байдингом, отдельно смысла от него ну совсем нет. Тестировать тоже с ним.
Давайте не будем забывать, что dependency properties это костыль, придуманный MS исключительно ради Attached properties, типо Grid.Column.
Это ваша додумка. Я с вами тут не согласен. Дам встречный вопрос: «Сколько значений в одно время может иметь Dependency Property?». Вот-вот, обычный CLR property такое не позволит, а в случае с анимацией, стилями — это полезная штука.
0
Binding произносится как байндинг согласно всем моим англоязычным коллегам. Но может они ошибаются, плохо знают родной английский.
Я сравнивал запись в свойство, а также возможность реагировать на изменение этого свойства изнутри класса. Понятное дело, что реагировать на изменение свойства хотелось бы в его родном виде, поэтому везде стоит typecast. Это мой обычный сценарий. Никаких натяжек.
Выигрывая в транспортировке значения как object в случае композитных data-binding, мы проигрываем в использовании этого свойства в коде, т.к. typecast и извлечение значение из Dictionary по ключу инстанса DependencyProperty — это все-таки накладные расходы.
Еще интересно покопаться в классах CLRPropertyListener и DependencyPropertyListener, станет ясно, что логика везде одинаковая…
Я не умоляю достоинств DependencyProperties, просто их место в контролах, которые уже написаны за нас. В статье же речь идет об удобном варианте создания ViewModel-ей. И как мне показалось, использовать DependencyObject в этом контексте не совсем разумно. Ну если только вам необходима анимация свойств у ваших ViewModel-ей :)
А насчет анимации — соглашусь, не подумал. Хотя уверен, что простые свойства тоже поддаются анимации. Другое дело, что это будет уже Frame-based, а не Time-based анимация, которой MS так гордится.
В итоге вы не сравнили ничего, точнее сравнили, но впустую. DependencyObject нужно использовать только в контексте с байдингом
Я сравнивал запись в свойство, а также возможность реагировать на изменение этого свойства изнутри класса. Понятное дело, что реагировать на изменение свойства хотелось бы в его родном виде, поэтому везде стоит typecast. Это мой обычный сценарий. Никаких натяжек.
Выигрывая в транспортировке значения как object в случае композитных data-binding, мы проигрываем в использовании этого свойства в коде, т.к. typecast и извлечение значение из Dictionary по ключу инстанса DependencyProperty — это все-таки накладные расходы.
Еще интересно покопаться в классах CLRPropertyListener и DependencyPropertyListener, станет ясно, что логика везде одинаковая…
Сколько значений в одно время может иметь Dependency Property?
Я не умоляю достоинств DependencyProperties, просто их место в контролах, которые уже написаны за нас. В статье же речь идет об удобном варианте создания ViewModel-ей. И как мне показалось, использовать DependencyObject в этом контексте не совсем разумно. Ну если только вам необходима анимация свойств у ваших ViewModel-ей :)
А насчет анимации — соглашусь, не подумал. Хотя уверен, что простые свойства тоже поддаются анимации. Другое дело, что это будет уже Frame-based, а не Time-based анимация, которой MS так гордится.
+1
Все верно, в реализации своих ViewModel лучший вариант — это INotifyPropertyChanged. В контролах DependencyProperty.
Это накладные расходы, но вот то, что это медленнее работает — это только ваша додумка. Еще раз: ваши тесты этого не подтверждают, они только проверяют то, что если в своем приложении реализовать свойства у какого-нибудь класса как обычные CLR с интерфейсом или как DependencyProperty (которые еще раз говорю в контексте не связывания с другими dependency property не имеют смысла). Вы не реализовали инфраструктуру WPF/Silverlight у себя в тестах.
И честно говоря, я не очень понимаю, зачем в этом месте что-то оптимизировать. Особенно в бизнес сценариях. Ну будет у вас DataGrid и 1000 ViewModel, а в каждом по 20 свойств, все из которых отображаете. Но не всех же 1000 моделей будут отображаться, у DataGrid есть виртуализация. 10 ms против 50 ms? Это выигрываем?
Выигрывая в транспортировке значения как object в случае композитных data-binding, мы проигрываем в использовании этого свойства в коде, т.к. typecast и извлечение значение из Dictionary по ключу инстанса DependencyProperty — это все-таки накладные расходы.
Еще интересно покопаться в классах CLRPropertyListener и DependencyPropertyListener, станет ясно, что логика везде одинаковая…
Это накладные расходы, но вот то, что это медленнее работает — это только ваша додумка. Еще раз: ваши тесты этого не подтверждают, они только проверяют то, что если в своем приложении реализовать свойства у какого-нибудь класса как обычные CLR с интерфейсом или как DependencyProperty (которые еще раз говорю в контексте не связывания с другими dependency property не имеют смысла). Вы не реализовали инфраструктуру WPF/Silverlight у себя в тестах.
И честно говоря, я не очень понимаю, зачем в этом месте что-то оптимизировать. Особенно в бизнес сценариях. Ну будет у вас DataGrid и 1000 ViewModel, а в каждом по 20 свойств, все из которых отображаете. Но не всех же 1000 моделей будут отображаться, у DataGrid есть виртуализация. 10 ms против 50 ms? Это выигрываем?
0
1000 моделей нужно заполнить данными до того, как хоть одна из них будут отображаться. Фактор 13 это много.
Это вместо 400ms получаем 5 секунд. 5 секунд 100% нагрузки на ядро.
Неудивительно, что потом люди начинают жаловаться, что Silverlight тормозит (или садит батарейки в моем планшете) :)
Давайте просто не будем писать тормозной код. Преждевременная оптимизация — это грех, согласен. Но выбор изначально тормозной технологии — 100% гарантия тормозов в будущем и существенные издержки на их устранение.
Врага нужно знать в лицо :)
Это вместо 400ms получаем 5 секунд. 5 секунд 100% нагрузки на ядро.
Неудивительно, что потом люди начинают жаловаться, что Silverlight тормозит (или садит батарейки в моем планшете) :)
Давайте просто не будем писать тормозной код. Преждевременная оптимизация — это грех, согласен. Но выбор изначально тормозной технологии — 100% гарантия тормозов в будущем и существенные издержки на их устранение.
Врага нужно знать в лицо :)
+1
Я не за DependencyProperty, так как уже говорил, что считаю их полезными только для собственных контролов. Я за использование Lambda варианта. А если будет проблема с производительностью в установке значений, то всегда можно сделать доп. метод для инициализации сущностей и т.п. В общем проблемы легко решаются.
0
По поводу DataGrid — как у Вас получилось достичь таких малых времён (50ms)?
У меня на проекте DataGrid с 30 строками и по ~10 свойств в каждой VM, даже при сортировке кликом по колонке (вне зависимости от того, встроенный сортировщик, или указан собственный) время перекомпоновки приближается к секунде.
У меня на проекте DataGrid с 30 строками и по ~10 свойств в каждой VM, даже при сортировке кликом по колонке (вне зависимости от того, встроенный сортировщик, или указан собственный) время перекомпоновки приближается к секунде.
0
А можно показать какой код сеттера то в итоге генерится?? И за счет чего он становится аж в 3 раза быстрее рукописного??
+2
А отлаживать такой код в студии возможно?
+1
Полный код теста в студию, плз. У меня особой разницы между Manual и Lambda нет.
+1
> Поэтому я, как неисправимый преждевременный оптимизатор, склоняюсь именно к INPC.
+2
однако, если переписать так, то разница будет абсолютно приемлимые 10%:
staticExpression<Func<LambdaNPC, string>> MyPropertyExpression = o => o.MyProperty;
private string _MyProperty;
public string MyProperty
{
get { return _MyProperty; }
set
{
if (_MyProperty == value)
{
return;
}
_MyProperty = value;
RaisePropertyChanged(MyPropertyExpression);
}
}
void RaisePropertyChanged<T>(Expression<Func<LambdaNPC, T>> raiser)
{
var e = PropertyChanged;
if (e != null)
{
var propName = ((MemberExpression)raiser.Body).Member.Name;
e(this, new PropertyChangedEventArgs(propName));
}
}
+1
За что боролись, на то и напоролись.
Кто-то хотел минимум кода при максимуме производительности ;)
Кто-то хотел минимум кода при максимуме производительности ;)
0
В данном случае производительность должна быть не «о ужас, ужас» — этого уже достаточно, т.к. reflection при байндинге более узкое место по производительности. Конечно, INPC — это абсолютно точно реализация аспекта императивным программированием. Но пока, увы ни C#, ни VS, как платформа разработки, недружественны к AOP.
0
.net 4.0? :(
насколько сильны завязки? хочу попробовать портировать под 2.0 и интересно, достаточно ли переработать linq, или завязано глубже?
насколько сильны завязки? хочу попробовать портировать под 2.0 и интересно, достаточно ли переработать linq, или завязано глубже?
0
Sign up to leave a comment.
Борьба с INotifyPropertyChanged или как я стал опенсорсником — 2