Pull to refresh

Comments 21

Последний пример (со слешами в разные стороны) — ад какой-то. Если в Grid.RowDefenitions можно расставить комментарии, чтобы объяснить какой RowDefinition что означает, то вот эта строка из звёздочек, пробелов и палочек — мрак.
Слеши нужны для определения минимальных и максимальных размеров колонок и строк. Во многих случаях можно обойтись и без них. Думаю, это не столь сложная логическая задача, понять принцип их действия. Зато при таком способе очень легко изменять сетку ячеек даже во время работы приложения, что можно увидеть в примере HelloAero.
Спасибо за замечание!
Я бы сказал то описание строк не страшнее описания геометрии Path объекта. Разметки размер сокращает сильно.
«Нужно понять и простить» принять.
Классические инжекции зависимостей в конструктор не самая лучшая практика.

Вы, наверное, забыли добавить ограничения? Например «во вью-модели в MVVM»? Потому что в общем случае ваш тезис, скажем так, спорен.

Да, существует множество Unity-контейнеров, реализующих такую функциональность

Каких-каких контейнеров?
Спасибо за замечания! Исправил спорные моменты. Да, инжекции в конструктор вью-моделей не лучший вариант.
Новое дыхание WPF. Поднимаемся выше MVVM

Название статьи вводит в заблуждение.
Ожидаешь увидеть нечто концептуально новое, а получаешь килограм синтаксического сахара и ведро костылей, которые после пары лет разработки в WPF каждый сам себе пишет в том или ином виде.
Сейчас у вас поверхностное видение библиотеки и это нормально, чтобы начать различать концептуальные моменты следует применить немного больше усилий для изучения.
То есть, библиотека на самом деле революционная, а проблема в статье, которая не смогла этого раскрыть?
На самом деле существует уже обширный ряд статей, которые более детально раскрывают новаторские идеи, применяемы ещё в предыдущей версии библиотеки. Кроме того, есть незнакомые мне люди, которых заинтересовали описываемые подходы и сама библиотека. Ознакомиться с другими статьями можете и вы по этой ссылке.

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

Скорее библиотека представляет далеко не ведро костылей, а аккуратный набор инструментов, который в умелых руках мастера творит чудеса. Является она итогом далеко не двух, а шести лет опыта активной работы над различными, успешно завершёнными, проектами, в том числе разрабатываемыми с нуля.
кросс-платформенных XAML-ориентированных приложений
Список платформ не нашёл нигде.
В папке Foundation есть файлик FYI.txt

Полностью поддерживаются:
• Windows Desktop (WPF)
• Windows Phone 7, 8 (Silverlight based)

Поддерживаются с небольшими ограничениями:
• Windows Store (RT)
• Universal Apps
• Xamarin
this[() => Text].PropertyChanged += (o, args) => {… };


Сразу вопрос встает: «А отписываться как?»
И второй следом: «А не будет ли память утекать, если не отписаться?»
Логичный вопрос. Обычно в реальной жизни необходимости отписки не возникает, но если всё-таки нужно, то лямбда-выражение заменяем классическим методом и отписываемся, как и всегда.

this[() => Text].PropertyChanged += OnTextChanged;
//...
this[() => Text].PropertyChanged -= OnTextChanged;

Если подписка выполняется внутри объекта this, то никаких утечек не произойдёт, поскольку всё замкнуто на сам объект.
При внешней подписке нужно предусмотреть отписку или ожидать момента, когда слушатель будет собран сборщиком мусора уже вместе с нашим объектом одновременно.
Подписываться на PropertyChanged внутри самого INotify… инстанса я не представляю зачем. А снаружи правильнее реализовать WeakEventManager с подпиской на конкретное свойство. Тогда и отписка необязательна. Поэтому неуверен, что описанная фича вообще будет востребована.
Подписываться на PropertyChanged внутри самого INotify… инстанса я не представляю зачем.
Почему нет? Взгляните на примеры, это распространённая и удобная практика. Например, при изменении свойства нужно выполнить какие-либо действия внутри вью-модели. Конечно, можно поместить вызов нужной логики в сеттер свойства, но это не очень красиво.

А снаружи правильнее реализовать WeakEventManager с подпиской на конкретное свойство. Тогда и отписка необязательна.
На текущий момент ни в одном проекте, где применялась библиотека, реальной необходимости в слабых подписках на PropertyChanged не возникало, поэтому сейчас всё реализовано классическим образом с упором на хорошую производительность. Но ничто не мешает использовать другой подход, ведь исходный код открыт.

Поэтому неуверен, что описанная фича вообще будет востребована.
В тех проектах, где использовалась библиотека, эта фича была востребована :)

Спасибо, что высказываете своё мнение!
На текущий момент ни в одном проекте, где применялась библиотека, реальной необходимости в слабых подписках на PropertyChanged не возникало, поэтому сейчас всё реализовано классическим образом с упором на хорошую производительность.

1. Приложения профилировали на тему утечек памяти? Как минимум инстансы ViewModel'ей легко могут утекать в случае, когда и если подписка делается снаружи. Памяти VM'ки потребляют немного сами по себе, но могут висеть в памяти и производить паразитные вызовы обработчиков событий и CanExecute у команд, например. Особенно доставляет хлопот дефолтный ComandManager WPF, который дергает CanExcute'ы после выгрузки контролов с UI. Стоит только поместить в CanExecute проверку состояния каких-то моделей и прочего стафа в бэке, и начинаются проблемы.
2. Опять же по производительности разница между Weak и класической подписками может быть несущественной. Безопасность важнее.

Почему нет? Взгляните на примеры, это распространённая и удобная практика. Например, при изменении свойства нужно выполнить какие-либо действия внутри вью-модели. Конечно, можно поместить вызов нужной логики в сеттер свойства, но это не очень красиво.

О да! Видел я примеры такого в реальных проектах. Вместо вызова метода UpdateЧеТоТам(value) в сеттере делается подписка на PropertyChanged + портянка if… else… в обработчике события с проверкой имени свойства.
Даже описанный в статье способ подразумевает, что в точке входа в VM (.ctor ??) размещается цепочка подписок на изменение конкретных свойств. И тогда либо опять создается по одному обработчику на свойство (суть приватный метод, который легко можно вызвать и из сеттера), либо конструктор распухает лямбдами, либо создается один метод типа SubscribePropertyChangedEvents также распухающий лямбдами.
Приложения профилировали на тему утечек памяти?
Конечно! В библиотеке много внимания этому уделено. Например, реализация контекстных команд (Context Commands) использует механизм слабых привязок на событие CanExecuteChanged, ведь это распространённая проблема, когда статическая вью-модель удерживает контролы, подписавшиеся на это событие, от сборки мусора.

Также динамическая локализация реализована путём расширения привязок (Binding Extensions), потому что привязка — это медиатор, который не удерживает от сборки мусора ни представление, ни вью-модель, но на это мало обращается внимания, хотя момент очень важный.

Насчёт подписок на PropertyChanged, да, точка входа (как правило метод Expose [это как Dispose, только наоборот]) «распухает лямбдами», но это намного удобнее — контролировать подписки и вызовы в одном месте, чем искать в разбросанном виде по самим свойствам, а также устанавливать очерёдность вызовов.
Насчёт подписок на PropertyChanged, да, точка входа (как правило метод Expose [это как Dispose, только наоборот]) «распухает лямбдами», но это намного удобнее — контролировать подписки и вызовы в одном месте, чем искать в разбросанном виде по самим свойствам, а также устанавливать очерёдность вызовов.


1. Читабельность кода с случае с длинной последовательностью лямбд будет хуже, чем у последовательности методов той же длины. Хотя это дело конвенций на проекте.
2. Можно сгрупировать методы, вызываемые в сеттерах в один #region. Можно сгруппировать методы еще и конвенцией наименования («если нужен метод от такого-то свойства, то искать методо вида SomePropPostSet(...)»). С решарпером легко будет набрать 4-5 заглавные буквы, и метод найден.
3. Не понял как простыня из лямбд в Expose решает проблему определения последовательности вызовов до запуска приложения. В рантайме в обоих подходах последовательность вызовов будет определяться по Call Stack. В случае с подписками, как указано в статье, Call Stack будет содержать промежуточные записи с активацией event PropertyChanged, если правильно понял логику.
1. Лямбда выражения просто заменить на методы, поэтому читабельность кода из-за этого вряд ли сильно ухудшится. Во многих же случаях, лямбда-выражение описывает нужную функциональность одной-двумя строками кода, тогда как аналогичный метод занимает при стандартном форматировании минимум пять строк. Эта проблема отчасти решена в C# 6.

2. Можно, конечно. Всегда существуют альтернативные решения. Но в плане соотношения лаконичности и читаемости кода, на мой личный взгляд, предложенный в статье подход очень даже хорош.

3. Например, в методе-обработчике события PropertyChanged есть if- или switch-конструкции, которые в зависимости от имени свойства выполняют ту или иную логику. Вполне может так случиться, что при изменении первого свойства, нужно поменять второе, из-за чего мы, например, рекурсивно зайдём в этот же обработчик, что не слишком удобно для дебага.
Sign up to leave a comment.

Articles