Comments 44
Основная проблема в том то, что вы в статику пытаетесь засунуть динамику. Отсюда и вопросы с производительностью, отладкой, null-значениями и т.д. А так, получается красивый велосипед, который я никогда использовать не буду…
+2
Поясните, пожалуйста, подробнее что Вы имеете в виду под «вы в статику пытаетесь засунуть динамику». Производительность такого биндинга такая же как если бы вы реализовали биндинг с использованием конвертера, поскольку само выражение преобразовывается в анонимную функцию один раз
+1
XAML — это статика и изначально не предназначен для логики (триггеры и т.д. не в счет).
«Производительность такого биндинга такая же как если бы вы реализовали биндинг с использованием конвертера» — вы замеряли? Конвертер реализован при помощи интерфейса, он не парсит строки, не преобразовывает их в выражения, поэтому в вашем случае очевидно, что производительность будет меньше.
«Производительность такого биндинга такая же как если бы вы реализовали биндинг с использованием конвертера» — вы замеряли? Конвертер реализован при помощи интерфейса, он не парсит строки, не преобразовывает их в выражения, поэтому в вашем случае очевидно, что производительность будет меньше.
0
да, замерял. Конвертер парсит строку 1 раз, по строке создается делегат, который ничего уже не парсит, а выглядит как функция, принимающая на вход source property и реализующая логику распарсенного выражения. Замер скорости ведется для всех биндингов из примера к библиотеке, которая лежит на github рядом с ним.
0
я не говорю о том, что в xaml следует переносить любую хоть немного сложную логику: операции с массивами, linq выражения, вызов функций из своих классов и т.д. но я считаю что простые выражения, которыми активно можно пользоваться в интерфейсе, могут и должны быть очевидным образом прописаны в xaml.
0
В CalcBinding нельзя задать свой собственный конвертер. Я не придумал сценария, в котором требовалась бы такая возможность, поэтому если у вас есть предложения, буду рад их прочитать.Есть два поля ввода. В одном —
http://example.com
, в другом — pic.jpg
. Нужно собрать путь из двух частей и показать картинку. С помощью CalcBinding решаемо?0
Спасибо, хороший пример! На первый взгляд решение без конвертера не нашлось
0
QuickConverter задавать Converter даёт, например.
0
Вы чемпион в дисциплине — «Что мне сделать чтобы не писать легко читаемый и трестируемый код во вью модели?»
В техническом плане — то что вы сделали — просто супер. Но я бы никогда не стал использовать это в продакшене. Все приведенный use-case намного проще (более читаемо и проще для тестирования) имплементировать на уровне view-model.
Но повторюсь — с технической точки зрения — просто прекрасно.
В техническом плане — то что вы сделали — просто супер. Но я бы никогда не стал использовать это в продакшене. Все приведенный use-case намного проще (более читаемо и проще для тестирования) имплементировать на уровне view-model.
Но повторюсь — с технической точки зрения — просто прекрасно.
+5
А вот такой кейс: ViewModel содержит высоту ячейки таблицы RowHeight. Каждая ячейка оборачивается в Border, у которого Thickness рассчитывается как (0, 0, ViewModel.RowHeight / 30.0, 0). Как это сделать красивее? Ввести свойство BorderThickness во вью-модели? Написать конвертер? На мой взгляд, предложенное в статье решение в данном случае было бы оптимальным, и для меня остается загадкой, почему разработчики WPF не предоставили такой возможности out-of-the-box.
+4
а просто показывать Thickness из view-model чем вам не нравится?
Как плюс — явная прозрачность алгоритма получения, отличная тестируемость (никакой разработчик вам никогда не сломает ваш алгоритм), возможность пробежать по крайним случаям (а что будет если например ViewModel.RowHeight = 0 ?).
Конвертор — это будет отдельный класс — согласен что для простой математической операции — оверкил, но при этом его тоже на порядок легче сопровождать.
ИМХО — xaml и так очень сложно читаемый язык программирования. Вынося в него логику — вы усложняете себе жизнь в дальнейшем.
Как плюс — явная прозрачность алгоритма получения, отличная тестируемость (никакой разработчик вам никогда не сломает ваш алгоритм), возможность пробежать по крайним случаям (а что будет если например ViewModel.RowHeight = 0 ?).
Конвертор — это будет отдельный класс — согласен что для простой математической операции — оверкил, но при этом его тоже на порядок легче сопровождать.
ИМХО — xaml и так очень сложно читаемый язык программирования. Вынося в него логику — вы усложняете себе жизнь в дальнейшем.
+1
Не соглашусь с Вами, что «более читаемо и проще имплементировать туже самую логику на уровне view-model» или конвертера. Конвертер выглядит сложнее и пишется дольше, а использование свойств для этих целей во вьюмодели загромождают её.
А что вы имеете в виду под сопровождением конвертера? Часто ли вы сопровождаете InverseBooleanConverter? Какие сложности сопровождения этого решения Вы видите кроме опасения того, что это сторонняя библиотека?
А что вы имеете в виду под сопровождением конвертера? Часто ли вы сопровождаете InverseBooleanConverter? Какие сложности сопровождения этого решения Вы видите кроме опасения того, что это сторонняя библиотека?
0
Конвертор как раз сопровождать просто (зафиксировать функциональность и написать тесты) так-же как и view-model. Сложно сопровождать xaml — а именно код в нем написанный.
Проблема в том что вы часть кода переносите в xaml — имхо порочная практика.
> а использование свойств для этих целей во вьюмодели загромождают её.
Имхо — нет. Ответственность view-model — это содержать логику работы view. Запрос веб странички — загромождает view-model, а вот как для этого ui-элемента конвертировать состояние в визуальное представление — нет.
Опять — же все сказанное ИМХО, наработанное за несколько лет ведения и развития нескольких длинных проектов на WPF (все проекты живут уже по 2-3 года и активно развивались без переписывания с нуля)
Проблема в том что вы часть кода переносите в xaml — имхо порочная практика.
> а использование свойств для этих целей во вьюмодели загромождают её.
Имхо — нет. Ответственность view-model — это содержать логику работы view. Запрос веб странички — загромождает view-model, а вот как для этого ui-элемента конвертировать состояние в визуальное представление — нет.
Опять — же все сказанное ИМХО, наработанное за несколько лет ведения и развития нескольких длинных проектов на WPF (все проекты живут уже по 2-3 года и активно развивались без переписывания с нуля)
+1
Аргумент против экспонирования толщины бордера во View-Model:
Изначальная задумка разработчиков WPF была в том, что XAML-представление должен рисовать дизайнер, а code-behind пишет разработчик. View-Model должна содержать данные для отображения, но не стилистические особенности элементов. В моём примере ширина бордера является 1/30 высоты ячейки, но в какой-то момент дизайнер может захотеть изменить это значение, и в этом случае ему придётся идти к программисту или самому лезть в код модели.
Конечно, концепция разделения зон ответственности дизайнеров и программистов с треском провалилась (по крайней мере, я не знаю ни одного живого примера), но к этому следует стремиться.
Изначальная задумка разработчиков WPF была в том, что XAML-представление должен рисовать дизайнер, а code-behind пишет разработчик. View-Model должна содержать данные для отображения, но не стилистические особенности элементов. В моём примере ширина бордера является 1/30 высоты ячейки, но в какой-то момент дизайнер может захотеть изменить это значение, и в этом случае ему придётся идти к программисту или самому лезть в код модели.
Конечно, концепция разделения зон ответственности дизайнеров и программистов с треском провалилась (по крайней мере, я не знаю ни одного живого примера), но к этому следует стремиться.
0
Согласен с вами. Ни на одном из моих мест работы я не увидел ни одного дизайнера, занимающегося разработкой интерфейса на wpf, все делает программист. А программисты очень не любят писать что то однообразное длинное и повторяющееся
0
>В моём примере ширина бордера является 1/30 высоты ячейки, но в какой-то момент дизайнер может захотеть изменить это значение, и в этом случае ему придётся идти к программисту или самому лезть в код модели.
>Конечно, концепция разделения зон ответственности дизайнеров и программистов с треском провалилась (по крайней мере, я не знаю ни одного живого примера), но к этому следует стремиться.
А зачем? Это не работает. Больше того — отдать xaml дизайнеру это получить либо проблемы в производительности, либо проблемы с разъезжающимся UI. ИМХО — с этим надо просто смирится и жить дальше. Уже сделали что дизайнер может разговаривать с разработчиком на одном языке (xaml), но допускать любого кроме разработчика к мастер ветке — это верный путь к багам.
>View-Model должна содержать данные для отображения
ИМХО но данным место в модели. Если у нас хранится высота колонки во вью модели, то и ширину ее бордера имеет смысл хранить и считать там-же (все в одном месте как минимум). View-Model это модель вьюшки и вся кастомная логика вью должна быть там.
>Конечно, концепция разделения зон ответственности дизайнеров и программистов с треском провалилась (по крайней мере, я не знаю ни одного живого примера), но к этому следует стремиться.
А зачем? Это не работает. Больше того — отдать xaml дизайнеру это получить либо проблемы в производительности, либо проблемы с разъезжающимся UI. ИМХО — с этим надо просто смирится и жить дальше. Уже сделали что дизайнер может разговаривать с разработчиком на одном языке (xaml), но допускать любого кроме разработчика к мастер ветке — это верный путь к багам.
>View-Model должна содержать данные для отображения
ИМХО но данным место в модели. Если у нас хранится высота колонки во вью модели, то и ширину ее бордера имеет смысл хранить и считать там-же (все в одном месте как минимум). View-Model это модель вьюшки и вся кастомная логика вью должна быть там.
0
>> Больше того — отдать xaml дизайнеру это получить либо проблемы в производительности, либо проблемы с разъезжающимся UI
Ну, это уж вопрос профессионализма дизайнера…
Ну, это уж вопрос профессионализма дизайнера…
0
Это вопрос сферичности дизайнера в вакууме. Много вы знаете дизайнеров UI, которые понимают все нюансы XAML?
0
Я, честно говоря, вообще не встречал в реальной жизни команд с UI-дизайнерами, т.к. мне приходится разрабатывать приложения, где заказчику важен функционал, а не рюшечки. Всё рисуем своими силами. Но надеюсь, такие команды всё же есть. И в моём понимании, если дизайнер работает в команде, использующей WPF, он должен не просто формочки в фотошопе клепать, а предоставлять на выходе полноценный макет на XAML-е, удовлетворяющий всем требованиям заказчика. И если по дизайну было требование, что ширина бордера должна быть 1/30 высоты ячейчи, то это задача не программиста, а именно дизайнера, на мой взгляд. Программист может даже не знать, в каком виде должны отображаться его данные — может, это вообще не таблица, а круговая диаграмма. Именно поэтому я считаю, что ViewModel не следует перегружать информацией о способе представления.
0
Насколько мне известно, таких дизайнеров сложно найти, и стоят они очень дорого, не каждая компания может себе позволить себе такое удовольствие. Если нашёл дизайнера, который хорошо разбирается в юзабилити, а не только раскрашивает картинки в фотошопе — уже радость.
Вообще, при всём разделении между логикой и представлением всё равно они тесно связаны, и логики во вьюхах до черта: триггеры, конвертеры, селекторы шаблонов, привязка к моделям и т.п. Я как программист лучше буду иметь свободу рефакторить код и держать его в чистоте, чем пускать в XAML дизайнера.
Вообще, при всём разделении между логикой и представлением всё равно они тесно связаны, и логики во вьюхах до черта: триггеры, конвертеры, селекторы шаблонов, привязка к моделям и т.п. Я как программист лучше буду иметь свободу рефакторить код и держать его в чистоте, чем пускать в XAML дизайнера.
0
Заставлять дизайнера ковыряться в XAML — примерно как заставлять его верстать HTML. То есть, крайне неэффективное применение.
0
В мире веб-разработки есть такая специализация — верстальщик. Поэтому там дизайнеры и программисты освобождены от этой рутины. (В отсутствии верстальщика этим, как правило, всё же занимается дизайнер).
В мире WPF такого выделенного человека нет, поэтому этим приходится заниматься программистам, ибо редкий дизайнер осилит.
В мире WPF такого выделенного человека нет, поэтому этим приходится заниматься программистам, ибо редкий дизайнер осилит.
0
Нет — вопрос профессионализма дизайна — это удобство тех интерфейсов которые он дизайнит — это все. Дизайнер не должен понимать что 2 лишних бордера в коллекции элементов, где смена элементов происходит часто — это проблема производительности. Это задача разработчика. И отвечает за это разработчик. И то что приложение может расползтись при разных DPI в системе — тоже забота разработчика. К дизайнеру это не имеет никакого отношения.
0
В данном случае за вас в общем виде уже написан, протестирован и готов к использованию конвертер, решающий определенный круг задач в общем виде. Выражение в binding выходит не сложнее того, что позволяет ввести обычный инженерный калькулятор. Если же вы в нем делаете ошибку, то у вас в output появится соответствующее сообщение в стиле binding errors. Если у вас все заработало, то тест пройден и это просто работает. Ошибки, которые вы можете поймать в дальнейшем, могут быть связаны с невалидными или отсутствующими данными, тогда вы увидите теже самые ошибки в output, что и при использовании стандартного binding.
Сложность в сопровождении составляет большой по объему код со сложной запутанной логикой, в данном же случае мы видим обратную ситуацию, кода мало он в одном месте, он выглядит очень просто, значит менять его не ожидая что где то, что то сломается можно без опасений
Сложность в сопровождении составляет большой по объему код со сложной запутанной логикой, в данном же случае мы видим обратную ситуацию, кода мало он в одном месте, он выглядит очень просто, значит менять его не ожидая что где то, что то сломается можно без опасений
0
Не все во ViewModel используют UI элементы.
0
Да, действительно. Из-за таких примеров, а также BoolToVisibility и InverseBool конвертеров и было предложено решение
0
В кросс-платформенной библиотеке MVVMCross для Xamarin Стюарт (автор) реализовал простой и понятный биндинг который он назвал Tibet:
а также особо полезные ValueCombiners типа IIF, Format >>>
Он так же предлагает реализацию Tibet для XAML в виде AttachedProperties
Интересно, почему не в виде MarkupExtension как в этом примере
Using these ideas, then a binding like:
Text TweetText, Converter=RemainingLength, ConverterParameter=140
might be rewritten:
Text RemainingLength(TweetText,140)
or perhaps even:
Text 140 - Length(TweetText)
а также особо полезные ValueCombiners типа IIF, Format >>>
Он так же предлагает реализацию Tibet для XAML в виде AttachedProperties
<TextBlock mvx:Bi.nd="Text Customer.FirstName; Visible=ShowFirstName" />
Интересно, почему не в виде MarkupExtension как в этом примере
0
Мне больше всего нравится подход reactiveui с биндингами в code behind.
Проверка корректности на этапе компиляции, интеллисенс, отсутствие необходимости написания конвертеров.
Проверка корректности на этапе компиляции, интеллисенс, отсутствие необходимости написания конвертеров.
0
Красивое решение. Очень хорошо подойдёт для каких-нибудь небольших проектов, которые нужно побыстрее и попроще сделать. Но, присоединюсь к bessony и onikiychuka, в большом продакшн-проекте я бы опасался использовать такой подход.
+1
Чем принципиально отличается от QuickConverter. Тем, что не умеет LINQ и сложные выражения?
0
Принципиально отличается двумя пунктами.
Первое, quick converter судя по всему не умеет вынимать из выражения path имена source property. Поэтому они используют простые стандартные шаблоны $p которые без труда можно найти. Из за этого вам приходится лепить эти конструкции с шаблонами а потом еще биндинги отдельно указывать, согласитесь выглядит не очень юзабельно. Я бы не хотел этим загромождать xaml, для меня, как автора либы, вопрос удобства использования стоял принципиально. В моем биндинге в path вы можете писать какие угодно свойства и вложенные в несколько других вью моделей и понескольку раз одно и тоже, словом как вам удобно вытащить данные. А вот свойства типа p0 p1 извините, выглядят как костыль или временное решение
Второе. В quick converter необходимо вручную забивать выражение для обратного биндинга из dependency property к source property. У меня, как описание в статье выше, выражение представляется в виде функции для которой автоматически ищется обратная и новое выражение служит для обратного связывания
Насчет плюсов quick converter: я считаю что уже Linq выражения это уж точно не обязанность представления, это довольно далеко от представления и это должно быть во вьюмодели, кстати это тот случай о котором писал onikiuchika, писать tostring с целью поменять формат выода в path тоже не следует, для этого есть прекрасное свойство string format в стандартном binding.
С учетом этого я не вижу сильных преимуществ quick converter перед моим решением.
Словом, мое решение требует от вас меньше кода, а возможностей, которыми вы реально будете пользоваться, дает больше
Первое, quick converter судя по всему не умеет вынимать из выражения path имена source property. Поэтому они используют простые стандартные шаблоны $p которые без труда можно найти. Из за этого вам приходится лепить эти конструкции с шаблонами а потом еще биндинги отдельно указывать, согласитесь выглядит не очень юзабельно. Я бы не хотел этим загромождать xaml, для меня, как автора либы, вопрос удобства использования стоял принципиально. В моем биндинге в path вы можете писать какие угодно свойства и вложенные в несколько других вью моделей и понескольку раз одно и тоже, словом как вам удобно вытащить данные. А вот свойства типа p0 p1 извините, выглядят как костыль или временное решение
Второе. В quick converter необходимо вручную забивать выражение для обратного биндинга из dependency property к source property. У меня, как описание в статье выше, выражение представляется в виде функции для которой автоматически ищется обратная и новое выражение служит для обратного связывания
Насчет плюсов quick converter: я считаю что уже Linq выражения это уж точно не обязанность представления, это довольно далеко от представления и это должно быть во вьюмодели, кстати это тот случай о котором писал onikiuchika, писать tostring с целью поменять формат выода в path тоже не следует, для этого есть прекрасное свойство string format в стандартном binding.
С учетом этого я не вижу сильных преимуществ quick converter перед моим решением.
Словом, мое решение требует от вас меньше кода, а возможностей, которыми вы реально будете пользоваться, дает больше
0
Первое, quick converter судя по всему не умеет вынимать из выражения path имена source property. Поэтому они используют простые стандартные шаблоны $p которые без труда можно найти. Из за этого вам приходится лепить эти конструкции с шаблонами а потом еще биндинги отдельно указывать, согласитесь выглядит не очень юзабельно. Я бы не хотел этим загромождать xaml, для меня, как автора либы, вопрос удобства использования стоял принципиальноМаленький ньюанс. Указание параметров через P0 выдерживает решарперовский Rename, а ваше решение — нет. Таким образом, XAML с использованием вашей либы становится неподдерживаемым средствами автоматического рефакторинга. Решение о том, что юзать в продакшн-проекте, думаю, очевидно.
0
Стоящее замечание, спасибо. То есть если я вас правильно понял решарпер в случае переименования свойства во вьюмодели изменит в xaml все биндинги к нему. А как он определит в design time что вьюха относится к определенной вьюмодели? Только по name convention?
0
<Window x:Class="WpfSandbox.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:wpfSandbox="clr-namespace:WpfSandbox"
d:DataContext="{d:DesignInstance Type=wpfSandbox:Mdl, IsDesignTimeCreatable=True}"
mc:Ignorable="d">
Вот так примерно делаете, после чего как студия, так и решарпер начинают понимать, какая к вьюхе привязана модель. Ну и дальше вниз по дереву уже сами выводят, если вы к какому-то свойству привязались.
0
Я правильно понял, что лямбда кэшируется в инстансе биндинга? Тогда возникает вопрос, что будет с производительностью, если в списке 50 элементов, и в шаблоне элемента пять вычисляемых биндингов.
0
Кешируется в инстансе конвертера. Объекты Binding и CalcConverter создадутся по одному разу для каждого вычисляемого биндинга, один раз скомпилируется выражение для каждого вычисляемого биндинга. И всё) А вы знаете как работают биндинги в списковых контролах типа DataGrid или ListView? У Вас и обычные биндинги тоже создадутся ровно столько раз, сколько они упомянуты в разметке, независимо от числа элементов.
0
Сейчас занимался сравнением производительности и для меня это тоже стало открытием, статей по поводу внутренней реализации не нашёл, остаётся только посмотреть, что внутри у этих контролов
0
Компиляция выражений — не самая шустрая процедура, вроде. Отражения медленнее, чем скомпилированное выражение, но из-за компиляции нужно немало вызовов, чтобы оно "окупилось".
Впрочем, без замеров не сказать, какие последствия будут на производительности.
0
По поводу того, что «Всякий раз… необходимо писать свой конвертер», всё уже написано до нас github.com/kentcb/WPFConverters. Поддерживаются и арифметические операции, и булевые, и много чего еще.
+1
А для 4 фремворка это чудо возможно?
0
Sign up to leave a comment.
WPF: Binding без тривиальных конвертеров