|
Модератор
|
||||||||||||||||||||||||||||||||||||
WPF команды и MVVM. Часть 1. [WPF, Элд Хасп]18.01.2019, 19:56. Показов 55896. Ответов 92
Тема из цикла Готовые решения, примеры и рекомендации начинающим на WPF [Элд Хасп]
Для использования и создания WPF команд в Net предусмотрен интерфейс IСommand и классы RoutedCommand и RoutedUICommand. Команда - это View компонента и ей присущи чисто View-ские свойства: можно привязать её, параметр передаваемый ей, целевой элемент; она может всплывать по дереву элементов; можно обработать её по по пути всплытия. Основная проблема применения команд в MVVM, на мой взгляд, это отсутствие встроенной поддержки привязки к методам ViewModel. Дефолтно в Net обработка команд производится аналогично обработке событий элементов в CB окна. И уже в в этом обработчике можно вызвать методы ViewModel. Но тут возникает другая проблема. Как обработчику получить ViewModel? Придётся обращаться к DataContext приводить к нужному типу, походу могут возникнуть ещё другие нюансы. Самым удобным было бы привязка команд в XAML напрямую, сразу к свойствам ViewModel. Для такой привязки в большинстве случаев создают дополнительный класс реализующий интерфейс IСommand. Почти всегда его называют RelayCommand. Реализации его могут быть разные, но они очень похожи. Одна из реализаций из темы Пример реализации WPF+MVVM приложения (с учётом замечания от Lexeq)
VievModel
И окно для PlusMinusViewModel
Изменим немного ViewModel для демонстрации обработки CommandParameter.
Окно для MultiOperatorsViewModel
Изменим ViewModel так чтобы нельзя было делить на ноль.
Использование WPF команд в MVVM для простых случаев, надеюсь, объяснил подробно и понятно. Но есть более сложные применения. Допустим, есть ListBox и в нём в шаблоне Item есть кнопка. Как к ней привязать WPF команду? Для этого надо вспомнить, что WPF команда это View компонента и одним и свойств WPF команды является её всплывание по дереву. Команду надо "поймать" во включающем ListBox контейнере и обработать. Как это сделать напишу в следующей части. Архив проекта с кодами приложен. Ещё хороший пример простой для понимания предложил Lexeq в пост #10 В пост #15 финальный вариант с учётом замечаний от HF, Lexeq, Рядовой, kolorotur. Там же архив со всеми кодами из темы. В пост #64 вариант реализации RelayCommand с исправленным (при помощи proa33 и kolorotur) методом Invalidate для работы в многопоточном приложении.
12
|
||||||||||||||||||||||||||||||||||||
| 18.01.2019, 19:56 | |
|
Ответы с готовыми решениями:
92
WPF команды и MVVM. Часть 2. Всплытие команд. Реализация команды для списка элементов [WPF, Элд Хасп] Библиотека элементов для реализации WPF MVVM Решений [WPF, Элд Хасп] Обсуждение темы "Библиотека элементов для реализации WPF MVVM Решений" [WPF, Элд Хасп] |
|
Модератор
|
||
| 13.02.2019, 14:11 [ТС] | ||
|
У меня одна Модель (из нескольких объектов). К ней подсоединены 2 ViewModel. При подсоединении первой VM она инициирует Model и они обмениваются данными. Через некоторое время (зависит от пользователя) создаётся вторая VM. Понятно, что при изменении данных VM2 изменит значения свойств. Но до изменения данных VM2 тоже надо инициировать свои свойства текущими значениями Model. Я поэтому так и сделал. После подсоединения прослушки, сразу посылается сигнал об изменении всех свойств. Автоматически VM2 свои свойства обновит. Если это убрать - тогда надо в коде VM2 прописать явное чтение всех свойств из Model после соединения. Получается дублирование кода. Обновление свойств и так уже записано в обработчике PropertyChange. Добавлено через 5 минут Даже, для первой VM. Она соpдаёт Model. После создания Model к ней подсоединяется прослушка. Но если при инициализации Model она изменит значения своих свойств, то VM об этом не узнает, так как прослушка подсоединится позже. И какое-то время, пока все свойства ещё раз не обновятся состояния Model и VM будут отличаться. Придётся, опять таки, явно после подсоединения прослушки VM считывать значения всех свойств. Хотя у WPF элементов такого не возникает. Там, интересно, как этот момент реализован?
0
|
||
|
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
|
||||
| 13.02.2019, 14:24 | ||||
|
Вы копируете значения свойств из модели в VM? А если знаете, то почему сразу после подписки в той же VM не вызвать OnAllPropertyChanged? А то как-то странно получается: модель должна знать о том, что VM должна обновить свои свойства?
0
|
||||
|
Модератор
|
||||
| 13.02.2019, 14:52 [ТС] | ||||
|
VM2 уже работает с другими свойствами и методами модели. Я думал в начале сделать общую VM..., но код получался какой-то монструозный, огромный. Поэтому разделил на две VM. ![]() А вот это мне в голову не пришло! ![]() Так действительно, будет разумнее! Добавлено через 4 минуты kolorotur, а с Invalidate какое оптимальный подход будет? И я так и не понял (в потоках токо-токо начинаю разбираться) из-за чего ошибка? Ведь там только код, визуализации нет.... Откуда потребность в одном потоке?
0
|
||||
|
Модератор
|
||||||
| 30.04.2019, 22:39 [ТС] | ||||||
Новая реализация RelayCommand с исправлениями от proa33 и koloroturКак выяснилось при многопоточной работе метод Invalidate (в реализации из поста #15) выдаёт ошибку. Обсуждение ошибки в постах #35-#57. proa33 и kolorotur нашли решение, но в полном виде я забыл его опубликовать. Выкладываю полную реализацию RelayCommand с решением указанной проблемы.
4
|
||||||
|
В поиске
103 / 51 / 17
Регистрация: 20.04.2014
Сообщений: 826
|
|||||||||||
| 07.05.2019, 19:14 | |||||||||||
|
Элд Хасп, может есть уже актуальная версия а я попал на устаревшую
Кликните здесь для просмотра всего текста
Но тут явно какое то извращенство. Либо я читаю не правильно? Передаем в OnPropertyChanged текст в виде массива разобрали количество не 0 и не 1 идем в OnPropertyChanged(names). там в цыкле пробегаемся по переданному массиву в котором возвращаемся обратно в OnPropertyChanged но уже с одним значением но опять его пытаемся разбить его повторно на массив Добавлено через 15 минут Почему к примеру не так? Или есть еще какие либо варианты которые могут пробраться и сломать логику? Кликните здесь для просмотра всего текста
1
|
|||||||||||
|
Модератор
|
||||||||||||
| 07.05.2019, 19:55 [ТС] | ||||||||||||
|
Самая простая реализация, которую использую для простых примеров
0
|
||||||||||||
|
В поиске
103 / 51 / 17
Регистрация: 20.04.2014
Сообщений: 826
|
||||||||
| 07.05.2019, 20:09 | ||||||||
зачем? или я не правильно понял?
1
|
||||||||
|
Модератор
|
|||
| 07.05.2019, 20:17 [ТС] | |||
OnPropertyChanged() без параметров. Очень удобно. Если меняешь название свойства - не надо следить за тем где его имя прописано.PropertyChanged без значения (то есть когда null или Empty) означает, что надо обновить все свойства.Я сам этого не знал. Когда поправили, то изменил реализацию.
1
|
|||
|
В поиске
103 / 51 / 17
Регистрация: 20.04.2014
Сообщений: 826
|
|||||||
| 07.05.2019, 20:35 | |||||||
|
А вот по поводу того что вы текст склеиваете потом разбиваете на массив может есть смысл сразу передать в виде массива
Добавлено через 8 минут Элд Хасп, а SetProperty и PropertyNewValue для чего нужны можно пример как их вы используете?
1
|
|||||||
|
Модератор
|
|||||||||||||
| 07.05.2019, 21:35 [ТС] | |||||||||||||
|
Там есть перегрузка принимающая список имён свойств. Но Ваш вариант со списком параметров (params string[] name) тоже добавлю. Он мне просто в голову не пришёл.
В основном два варианта. Первый это обработка всех сеттеров в одном месте, а не в сеттере каждого свойства. Для одного свойства вот так ещё пойдёт
Раскидывать это по всему коду класса очень не удобно. Создаётся partial класс и в отдельном файле через переопределение SetProperty или PropertyNewValue перехватываются установка значений свойствам. оттуда уже идёт, если надо, ветвление по методам. Все методы в одном месте. Удобно, прозрачно, читаемо.Второе применение это способ сделать тоже самое в производном классе. В этом случае по другому просто невозможно. Я очень часто использую базовый класс и потом производные от него. Мне так удобно. Подобный метод есть у всех Net классов реализующих INPC. Попробуйте в CB окна вызвать список переопределяемых методов. Среди ни будет и void OnPropertyChanged(DependencyPropertyChangedEventArgs e) предназначенный для того же самого.
1
|
|||||||||||||
|
В поиске
103 / 51 / 17
Регистрация: 20.04.2014
Сообщений: 826
|
|||||||
| 07.05.2019, 22:32 | |||||||
|
Видимо представить себе такую картину не смог и как то проигнорировал OnPropertyChanged(new string[]{"Поле1","Поле2",..}) + то что эти два метода как то показались зацыкленными OnPropertyChanged первый ссылается на второго, а второй на первый Но больше всего мне не нравится то что много раз делаете действие одно и тоже Повторюсь еще может так будет понятнее к примеру (из 66 поста код ниже слов Сам использую такую) Случай 1 выполняем так OnPropertyChanged("") первая проверка положительно оповещаем все контролы чтобы обновились. дальше идем пытаемся "" разбить на массив у нас не получается names.Length=0 мы еще раз оповещаем все контролы чтобы обновились. Если я правильно понимаю мы 2 раза заставляем перерисовать те поля которые при биньженые. случай 2 OnPropertyChanged("Поле1/rПоле2") первая проверка отрицательна разбиваем на массив из 2 полей передаем массив в OnPropertyChanged(IEnumerable<string> propList) там фильтруем и перебираем И ВОЗВРАЩАЕМСЯ НАЗАД где опять но уже над одним словом Поле1 первую проверку проходим на отрицательно опять пытаемся из неё сделать массив и поняв что во второй раз уже не получается только потом говорим что надо оповестить контрол об изменении и с Поле2 та же процедура а если полей 100))) их как минимум по 2 раза одну и туже операцию с ними проводите. Правильно ли я размышляю? Если правильно то моё мнение лучше работать с массивом string и составляя его с помощью nameof() уже сразу, а не играться и разбивать его. Хотя на сколько я знаю если работать с библиотекой mvvm light то они уже реализовали RelayCommand и INotifyPropertyChanged но могу ошибаться. Я бы наверное просто бы добавил к той вашей самой простой реализации и наверно это и будет на все случаи жизни. name проверять на null думаю бессмысленно так как на это OnPropertyChanged(null) компилятор ругается
Добавлено через 3 минуты И если не сложно можете еще раз выложить пример когда в RelayCommand вылетала ошибка на многопоточной ситуации? а то я не понял как её получить при старом коде Добавлено через 19 минут
1
|
|||||||
|
Модератор
|
|||||||||
| 07.05.2019, 22:59 [ТС] | |||||||||
|
Моя оплошность! Уже запутался в реализациях.
0
|
|||||||||
|
Модератор
|
|||||||
| 07.05.2019, 23:00 [ТС] | |||||||
Новая реализация OnPropertyChangedClass Сам задумывался, что возможно это излишне. Но иногда была необходимость известить о нескольких свойствах, поэтому использовал такой способ. Но сейчас уже изменил стиль программирования (по мере набора опыта) и уже этим пользуюсь очень редко. А после дополнения перегрузки с Ваши вариантом params string[] propList - это, вообще, потеряло смысл.Сейчас лучше использовать такую реализацию
5
|
|||||||
|
Модератор
|
||
| 07.05.2019, 23:00 [ТС] | ||
|
В событии обработки изменения стояла проверка некоторых условий и, если условия менялись, вызывался метод Invalidate. Появлялась указанная ошибка. Если же не вызывать этот метод, то кнопка не становилась активной пока что-то на форме не поменяется. А если окно не в фокусе, то вообще состояние кнопки не менялось.
0
|
||
|
WPF Разработчик
463 / 167 / 42
Регистрация: 20.02.2018
Сообщений: 285
|
|||||||||||
| 08.11.2019, 15:17 | |||||||||||
|
Элд Хасп,
Объясните пожалуйста. Вы пишите команды вот в таком виде, через проверку на null
Как это вижу в реализации через Конструктор: •оптимизированно (инициализация один раз, объявление поля команды как readonly) •читабельно и эстетично(наглядно видно какие методы переданы во все команды) Свойство •оптимизированно (команда инициализируется только тогда, когда она понадобиться) •громоздко (слегка длинная конструкция, но да, здесь можно по разному обыграть решение, к примеру сделать статический метод которому передаётся поле по ссылке, и в зависимости от ситуации он создаст и вернём, либо просто вернёт значение) •практично(Когда мы переходим из редактора xaml на свойство команды нам надо знать переданный метод, так более практично, в отличии от конструктора, при котором нам надо перейти в конструктор и отыскать в нём инициализацию команды) Подводя итоге свойства оказываются менее производительными для постоянного вызова команды, поскольку постоянно проверяется if, так же свойства менее эстетично выглядят, однако они более практичны для разработки и отладки приложения
0
|
|||||||||||
|
Модератор
|
|
| 08.11.2019, 17:25 [ТС] | |
|
sttrox, я использую и так, и этак.
Часто конструктор VM, вообще, не создаю. И создавать его только ради инициализации команды? Второе, часто инициализация команды содержит логику, а порой и полные коды методов команды. Зачем это всё в конструкторе? Это только запутает код. Третье, скорость проверки на null очень высокая. Я сомневаюсь даже что каким-либо тестом удастся выявить задержку между при такой проверке. Тем более что это свойство только для чтения и обращение к нему от WPF элемента будет однократным.
0
|
|
|
WPF Разработчик
463 / 167 / 42
Регистрация: 20.02.2018
Сообщений: 285
|
||||||
| 08.11.2019, 17:46 | ||||||
|
Элд Хасп, Позвольте, но тогда зачем нам поле, если вызов происходит один раз?
Мы может спокойно написать
Проверял в отладчике, вызов этого свойства происходит действительно один раз.
0
|
||||||
|
WPF Разработчик
463 / 167 / 42
Регистрация: 20.02.2018
Сообщений: 285
|
|
| 08.11.2019, 18:05 | |
|
Элд Хасп, что плохого в том, что у нас будет несколько разных экземпляров команды? Какие могут быть последствия?
0
|
|
|
Модератор
|
|
| 08.11.2019, 18:18 [ТС] | |
|
sttrox, засорение памяти.
Иногда бывают реализации где элемент обращающийся к команде много раз пересоздаётся и каждый раз будет создаваться новый экземпляр команды. Для простых случаев можно не заморачиваться, но это создаёт привычку к плохому коду. Лучше привыкать всегда делать однотипно и правильно.
0
|
|
| 08.11.2019, 18:18 | |
|
Помогаю со студенческими работами здесь
80
Создание приложения "Штатное Расписание" в паттерне MVVM [WPF, Элд Хасп] WPF конвертеры [Элд Хасп] WPF vs WinForms (для начинающих) [Элд Хасп] Готовые решения, примеры и рекомендации начинающим на WPF [Элд Хасп]
Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |
|
Новые блоги и статьи
|
||||
|
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта
Симптом:
После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
|
Access
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
|
Новый ноутбук
volvo 07.12.2025
Всем привет.
По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне:
Ryzen 5 7533HS
64 Gb DDR5
1Tb NVMe
16" Full HD Display
Win11 Pro
|
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
|
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
|
|
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов
На странице:
https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/
нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
|
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов.
. . .
|
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
|
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
|
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут.
В век Веб все очень привыкли к дизайну Single-Page-Application .
Быстренько разберем подход "на фреймах".
Мы делаем одну. . .
|