Модератор
![]() ![]() |
|
Библиотека элементов для реализации WPF MVVM Решений [WPF, Элд Хасп]27.11.2020, 19:21. Показов 12978. Ответов 15
Решил собрать элементы используемые в темах в этом разделе.
В библиотеку включаю элементы которые, на мой взгляд, имеют универсальное применение не жёстко связанное с какой-то определённой задачей. Исходные коды на GitHub https://github.com/WpfMvvm. Пакеты будут также заливаться на NuGet. В состав пакетов включена полная XML документация. В этой теме будут примеры по использованию элементов, типов. Исходные коды будут приводиться только там где это необходимо для прояснения работы. Эта тема закрыта. Всё обсуждение, рекомендации, вопросы и т.п. будут в теме: Обсуждение темы "Библиотека элементов для реализации WPF MVVM Решений" [WPF, Элд Хасп] Выкладывать пакеты буду по мере их готовности. Для примеров будут только исходные коды на https://github.com/WpfMvvm/WpfMvvm.Examples
4
|
27.11.2020, 19:21 | |
Ответы с готовыми решениями:
15
Обсуждение темы "Библиотека элементов для реализации WPF MVVM Решений" [WPF, Элд Хасп] WPF команды и MVVM. Часть 2. Всплытие команд. Реализация команды для списка элементов [WPF, Элд Хасп]
|
Модератор
![]() ![]() |
|||||
27.11.2020, 19:25 [ТС] | |||||
3
|
Модератор
![]() ![]() |
|||||||||||||||||||||||||||||||||||||||||||||||||||
27.11.2020, 20:29 [ТС] | |||||||||||||||||||||||||||||||||||||||||||||||||||
Простейший конвертер реализующий логическое отрицание.BooleanNotConverter Код методов конвертера очень прост и одинаковый для обоих методов:
Можно обращаться к его статическому экземпляру:
Полные коды конвертера, расширения разметки и примера
0
|
Модератор
![]() ![]() |
|||||||||||||||||||||
27.11.2020, 20:44 [ТС] | |||||||||||||||||||||
Часто возникает (как мне кажется) задача преобразования значения в другой тип эквивалентно тому как это делают привязки.DefaultValueConverter К сожалению конвертер осуществляющий это преобразование доступен только внутри сборки (модификатор internal): https://referencesource.micros... 3beb6d4d79. В моём конвертере происходит (с использованием к рефлексии) получение этого конвертера и применение его к значению. Предусмотрена передача в конвертер типов целевого свойства и свойства источника (для обратного преобразования). Также создано расширение разметки для облегчения использования конвертера в XAML. Пример его использования:
Из этого свойства мы уже можем получить отдельно каждое из свойство Point. Очень часто задача преобразования типа встречается при передаче значения в параметр команды с обобщённым типом. Так как свойство CommandParameter имеет тип Object, то привязка к нему не делает никаких преобразований. В тоже время, реализаций команды с обобщённым типом предполагает получение в параметре типа приводимого к использованному и получения в другом типе (чаще всего в String) приводит к ошибке. Для решения этого приходится в ViewModel добавлять свойство этого типа, только с целью получения автоматического преобразования типа. И в параметр передавать не исходное значение из View, а значение этого свойства. Пример реализации команды с обобщённым типом:
Кнопка с конвертером получает уже Point и, если в TextBox корректное значение, кнопка активируется.
1
|
Модератор
![]() ![]() |
|||||||||||||||||||||
27.11.2020, 21:03 [ТС] | |||||||||||||||||||||
Конвертеры позволяющие соединить несколько конвертеров в цепочку.ChainOfConverters и ReadOnlyChainOfConverters У ChainOfConverters эта цепочка мутабельна и его легко использовать в XAML. У ReadOnlyChainOfConverters задаётся один раз в конструкторе и после этого её изменить нельзя. Он предназначен для использования в коде C#. Для примера простой конвертер для получения по bool значению двух цветов:
И получить мы её можем так:
Но можно задать статические экземпляры для прямой и инверсной привязки:
0
|
Модератор
![]() ![]() |
|||||||||||
27.11.2020, 21:03 [ТС] | |||||||||||
Имеющийся в Net конвертер обеспечивает привязку bool к видимости и для false возвращается коллапс.BooleanToVisibilityConverter и BooleanToVisibilityHiddenConverter Но иногда возникают задачи в которых надо получить инверсную привязку и/или вместо коллапса получить скрытие элемента. В конвертере BooleanToVisibilityHiddenConverter заменяется значение Visibility.Collapsed, возвращаемое BooleanToVisibilityConverter, на значение Visibility.Hidden. Инверсные версии конвертеров получаются с использованием цепочки конвертеров:
Пример использования:
0
|
Модератор
![]() ![]() |
|||||||||||
28.11.2020, 08:57 [ТС] | |||||||||||
Конвертер для трассировки привязок.TraceConverter Выводит во время Отладки в окно Вывода получаемое/возвращаемое значение Привязки. Конвертер никак не изменяет входное значение. Если входное значение имеет тип String, то его вывод обрамляется кавычками. Для отличия выводов из разных точек предусмотрено свойство Title, со значения которого будет начинаться строка вывода. В расширении разметки оно может передаваться первым неименованным параметром. Пример использования:
В цепочке TraceConverter может быть перед проверяемым конвертером (то есть между ним и целевым свойством) и/или после. Положение конвертера указывается в свойстве AfterBefore расширения разметки значением перечисления AfterBeforeEnum. Может передаваться неименованным параметром. В примере соединение в цепочку TraceConverter -> BooleanNotConverter -> TraceConverter. Трассируется значения передаваемое в конвертер и возвращаемое им.
0
|
Модератор
![]() ![]() |
||||||
28.11.2020, 09:06 [ТС] | ||||||
Часто возникающая задача: Получение списка значений перечисления.EnumValuesConverter Конвертер возвращает Array со всеми значениями перечисления. Перечисление может передаваться как тип или как одно из его значений. Может быть передано в источнике, или в параметре конвертера. У источника приоритет выше. Примеры использования:
0
|
Модератор
![]() ![]() |
|||||||||||
28.11.2020, 09:21 [ТС] | |||||||||||
Конвертер сравнивающий значение с параметром.EqualsConverter В свойстве IsNot можно задать инверсию сравнения. В обратной конвертации при значении true (если задана инверсия, то при false) происходит присвоение источнику параметра конвертера. Иначе присвоение не происходит - возвращается Binding.DoNothing. Применение конвертера может быть весьма различно. В примере показано использование для придания группе CheckBox поведения сходного с RadioButton.
Они связываются между собой через свойство-источник и поэтому наличие общей группы не играет значения:
0
|
Модератор
![]() ![]() |
|||||||||||||||||||||
28.11.2020, 09:29 [ТС] | |||||||||||||||||||||
Возвращает тип значения.GetTypeConverter В примере показано использование для задания разным типам разных шаблонов представления. Классы фигур:
1
|
Модератор
![]() ![]() |
|||||||||||||||||||||||||||||||
28.11.2020, 10:06 [ТС] | |||||||||||||||||||||||||||||||
DictionaryConverter для преобразования значения использует словарь.DictionaryConverter и DictionaryTypeConverter Словарь может быть передан в свойстве Dictionary или в параметре конвертера. DictionaryConverter производный от Freezable и свойство Dictionary может быть привязано. Приоритет у параметра конвертера выше чем у свойства Dictionary. В статическом свойстве Instance предоставлен замороженный экземпляр конвертера. Пример использования. ViewModel:
DictionaryTypeConverter отличается тем, что если значение имеет не тип Type, то для ключа используется не само значение, а его тип. Если такого типа в ключах словаря нет, то можно быть произведён поиск базовых типов. Включение такого поиска задаётся в свойстве UseBasicTypes. В статических свойствах InstanceBaseTypes и InstanceEqualsTypes предоставлено два замороженных экземпляра конвертера, соответственно, с использованием базовых типов и только эквивалентных. В расширении разметки свойством UseTypes задаётся какой из конвертеров будет возвращён. Пример использования. ViewModel:
Подразумевается, что в конвертер передаётся статический словарь, то есть задаваемый один раз до показа (Loaded) элемента с привязкой использующей этот конвертер. Так как используется обычный конвертер (а не мульти), то обращение к нему происходит только при изменении значения свойства источника. Изменение словаря не обновит привязку. Это видно в последнем примере, в режиме разработки, названия фигур не выводятся. Так как события Loaded не происходит. А словарь из ресурсов привязывается уже после создания вложенных элементов Окна. А при запуске приложения происходит событие Loaded, по которому происходит перепроверка всех привязанных значений. На этот момент словарь уже привязан и названия фигур нормально выводятся.
1
|
Модератор
![]() ![]() |
|||||||||||
28.11.2020, 20:44 [ТС] | |||||||||||
Конвертер вычисляющий простые арифметические выражения.ExpressionConverter Для получения строкового выражения из привязок используется метод Format(String, Object[]). Для строки составного формата используется либо параметр конвертера, либо значение первой привязки. Для вычисления полученного выражения в строке используется метод DataTable.Compute(String, String). Первым значением передаются полученная строка с выражением, вторым - пустая строка. Конвертер можно использовать как обычный конвертер для одного значения:
2
|
Модератор
![]() ![]() |
|||||||||||||||||||||
12.12.2020, 21:06 [ТС] | |||||||||||||||||||||
Реализация ICommand для общего применения.RelayCommand и RelayCommand<T> общего применения Дополнительно к интерфейсу добавлен метод для подъёма события CanExecuteChanged и свойство с типом методов команды.
От этого класса создан производный RelayCommand<T>, принимающем в конструкторе делегаты методов с обобщённым параметром. Для методов с object параметром и с обобщённым параметром объявлены делегаты:
Так же надо "в ручную" отслеживать изменение объектов от которых зависит состояние команды. Это позволяет уменьшить издержки вносимые реализаций команды. Эти реализации, в том числе, могут применяться в UWP, так ка в нём нет CommandManager и надо обеспечивать запуск приложений на "слабых" устройствах. Так же эти реализации могут применяться слоях не связанных с GUI. Для WPF использование этих реализаций потребует дополнительного кода для вызова события RaiseCanExecuteChanged(). При этом порой с неочевидной реализацией. Ниже показан пример использования этих классов. Обратите внимание на кнопку "Команда с bool параметром". В ней задана привязка параметра напрямую к UI элементу. И она работает как бы в противофазе к привязанному значению. Связанно это с тем, что привязка в изменяемом свойстве срабатывает ДО изменения в свойстве. Поэтому сеттер свойства IsHello, в котором вызывается метод RaiseCanExecuteChanged(), вызывает обновление команды ещё до того как в параметр команды по привязке поступит новое значение. Так же в примере демонстрируется, что передача в метод параметра в типе не приводимом по шаблону к типу методов, полученных в конструкторе, вызовет исключение. Для WPF более понятно и ожидаемо будет использование DefaultValueConverter и отсутствие исключения. Демонстрационный пример:
1
|
Модератор
![]() ![]() |
|||||||||||||||||||||
12.12.2020, 22:44 [ТС] | |||||||||||||||||||||
Для облегчения использования команд в WPF необходимо добавить автоматическую подписку метода RaiseCanExecuteChanged() на событие CommandManager.RequerySuggested.RelayCommand и RelayCommand<T> для применения в WPF Так же нужно предусмотреть создание CanExecuteChanged только в потоке диспетчера. Для этого в команду добавляется свойство Dispatcher из интерфейса
Если используется конструктор без явного задания диспетчера, то команда его получает из свойства Application.Current.Dispatcher. В основном в WPF команды используются в свойствах "только для чтения" и задаётся экземпляр живущий всё время жизни приложения. На случай необходимости явного уничтожения экземпляра команды необходимо в команде реализовать интерфейс IDisposable. Но я посчитал это избыточным и отказался от его реализации. Пример использования аналогичен примеру из поста RelayCommand и RelayCommand<T> общего применения . За исключением только команды в кнопке "Команда для проверки конвертации string в bool". Изменяя значение в текстовом поле видно, что текст корректно преобразуется в bool значение. В реализации VM уже нет необходимости в явном вызове метода RaiseCanExecuteChanged(). Поэтому из VM даже убрана реализация INPC.
1
|
Модератор
![]() ![]() |
|||||||||||
12.12.2020, 22:59 [ТС] | |||||||||||
Класс очень простой.Простые реализации: Базовый класс для ViewModel - BaseInpc Большая его часть это XML документация. Кроме события PropertyChanged и метода для его создания RaisePropertyChanged(), добавлены метод Set для изменения значения свойства и метод OnPropertyChanged, который переопределяется в производном классе для реализации зависимости от свойств.
Пример использования:
3
|
Модератор
![]() ![]() |
|||||||||||
12.12.2020, 23:00 [ТС] | |||||||||||
Базовый класс основан на Новая реализация RelayCommand с исправлениями от proa33 и kolorotur [WPF, Элд Хасп].RelayCommand и RelayCommand<T> Отличается названием метода для генерации события и конструктором для методов без параметра.
Object параметр приводится к обобщённому сопоставлением с шаблоном, поэтому тип отличный от требуемого должен быть конвертирован до привязки к праметру команды.
В применении эти классы аналогичны RelayCommand и RelayCommand<T> для применения в WPF .
4
|
12.12.2020, 23:00 | |
Помогаю со студенческими работами здесь
16
Создание приложения "Штатное Расписание" в паттерне MVVM [WPF, Элд Хасп] WPF vs WinForms (для начинающих) [Элд Хасп] Пример создания приложения для тестирования [WPF, Элд Хасп] WPF конвертеры [Элд Хасп] Непростое Решение для простой часто встречающейся задачи. Привязка TextBox к численному свойству [WPF, Элд Хасп] Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |
|
Новые блоги и статьи
![]() |
||||
Защита API Spring Boot с помощью шлюза JWT
Javaican 01.09.2025
В 2023 году, согласно отчёту OWASP, нарушения аутентификации и управления сессиями остаются в топ-3 самых критичных уязвимостей веб-приложений. На мой взгляд, это происходит не из-за отсутствия. . .
|
Архитектура ПО для разработчиков или Зачем нам системное мышление
ArchitectMsa 31.08.2025
Давай я расскажу, что происходит в большинстве проектов, с которыми мне приходилось работать. Вначале всё выглядит прекрасно: чистые интерфейсы, продуманные абстракции, явные зависимости. А через. . .
|
Пик Победы
XLAT 30.08.2025
Pmb__mCLTFM
|
Kafka и SQS: сравнение инструментов потоковой передачи
AI_Generated 30.08.2025
Сегодня я хочу поговорить о двух титанах в мире потоковой передачи данных: Apache Kafka и Amazon SQS. Или, как я их называю - "тяжелая артилерия" и "снайперская винтовка" в арсенале современного. . .
|
Python и FastAPI: руководство для начинающих
py-thonny 30.08.2025
FastAPI появился относительно недавно (в 2018 году), но уже успел стать популярным по всему миру. И причин тому несколько.
Во-первых, скорость. FastAPI основан на Starlette и Pydantic, что делает. . .
|
Системное мышление: как подходить к решению сложных программных проблем
ArchitectMsa 29.08.2025
Когда я только начинал свой путь в разработке крупных систем, у меня была наивная вера в то, что любую проблему можно решить, просто написав хороший код. Потом я столкнулся с реальностью - даже. . .
|
Статический ИИ-анализ: устранение утечек памяти в C с помощью DeepCode
bytestream 28.08.2025
Мой первый серьезный проект на C - система обработки финансовых транзакций для одного банка. Мы обрабатывали миллионы транзакций в день, и всё работало как швейцарские часы. . . первые две недели. А. . .
|
К сожалению, я снова начал движение в мир динозавров
Etyuhibosecyu 27.08.2025
Мой самый главный проект больше не может быть обновлен под актуальные версии движка. И если в прошлый раз это было потому, что компьютер не "тянул" - серьезная и весомая причина - то сейчас движок. . .
|
Как работать с модулем ESP-12E NodeMcu V3 в ArduinoIDE
Wired 26.08.2025
Когда я впервые держал в руках NodeMcu, то не мог поверить, что такой малыш с ценником в пару долларов может похвастаться встроенным Wi-Fi и приличной вычислительной мощностью. Это же настоящий. . .
|
Создание агентов LangChain для LLM на Python
AI_Generated 25.08.2025
Эх, помню времена, когда все мы восхищались простыми чат-ботами на основе больших языковых моделей! Напишешь запрос, получишь ответ — и вроде бы магия. Но потом наступает разочарование: модель не. . .
|