|
3 / 3 / 0
Регистрация: 13.07.2020
Сообщений: 229
|
||||
WPF MVVM бизнес логика и Model02.11.2021, 00:10. Показов 16210. Ответов 132
Всем привет!
Я уже довольно долго пытаюсь разобраться что же представляет из себя архитектура MVVM, конкретно задачи View и ViewModel мне понятны. Но остается вопрос что из себя представляет Model? Много где есть определение Model = бизнес логика. Но как понять какую логику отнести к модели, а какую например к сервису. К сожалению толкового ответа я не нашел, может плохо гуглил. В уроках обычно банальные примеры с расселением студентов по комнатам, что редко отображает реальное использование программы. На YouTube смотрел уроки по созданию MVVM приложению от Павла Шмачилина(https://www.youtube.com/watch?... P4&t=3630s), но именно про архитектуру он рассказывает не настолько подробно как хотелось бы. Все что я понял это то что Model занимается некими правилами записи и получения данных из сервисов. Также предоставляет данные для ViewModel. Тоесть та самая бизнес логика (про нее я смотрел https://www.youtube.com/watch?v=9DW-xdwjop8) и преобразование данных. Но уверенности что я все понял как нужно, нет. Ниже приведены примеры с которыми я сталкивался, но понятного для меня решения не нашел.
0
|
||||
| 02.11.2021, 00:10 | |
|
Ответы с готовыми решениями:
132
Model в MVVM
|
|
3 / 3 / 0
Регистрация: 13.07.2020
Сообщений: 229
|
||
| 01.12.2021, 15:38 [ТС] | ||
|
0
|
||
|
Модератор
|
||
| 01.12.2021, 20:10 | ||
|
Может надо их просто включать-отключать, а не Модель им передавать? То есть это часть БЛ Модели или отдельный от неё сервис?
0
|
||
|
3 / 3 / 0
Регистрация: 13.07.2020
Сообщений: 229
|
||
| 02.12.2021, 04:53 [ТС] | ||
![]() Вот представьте есть у нас монитор. Пользователь задает время включения ночного режима и время включения дневного режима. Между ночным и дневным режимом программа ставит ночную гамму, между дневным и ночным дневную гамму. В коде это работает так: есть коллекция мониторов(модель которая хранит ссылки на них) и сервис постоянно проверяет условия которые выставил пользователь для монитора. Тоесть в каком периоде сейчас работать(день, ночь), должен ли быть плавный переход гаммы(чтобы пользователь не ослеп при резком наступлении дневного периода), если ли у пользователя активное полноэкранное приложение(тогда активируется плавный переход от текущей гаммы к дневной) и т.п. Является ли сервис частью модели которая содержит в себе ссылки на мониторы я сказать не могу, мне кажется что можно сделать его и так и так, но раздельный вариант выглядит по моему лучше так как он выполняет много отличной от модели работы. Я доделал третию версию модели, посмотрите пожалуйста как будет время.
0
|
||
|
Модератор
|
|||||
| 02.12.2021, 13:13 | |||||
|
В такой реализации - создавать и удалять Мониторы может только Основная Модель. Но сами мониторы теперь тоже самостоятельные Модели. Поэтому, в принципе, можно открыть конструктор и пусть их создаёт кто хочет. Здесь вопрос больше в том, а как конструктор поместить в интерфейс? Второй вопрос, если у Монитора оставить открытый конструктор на уровне Модели (допустим для сервисов) и Мониторы будет создавать не Основная Модель, то как об этом она "узнает"? То есть нам нужны либо стриги правила как надо правильно создавать новые Мониторы, либо надо учитывать в логике, что могут быть Мониторы, которые не входят в коллекцию основной Модели. То есть оно как бы можно, но появляется куча дополнительных нюансов которые нужно учитывать. И текущая реализация с хендлерами - это по сути и есть ограничивающие правила, чтобы отсечь не нужную нам функциональность и упростить логику слоя. Так как у нас сейчас есть публичный IMonitorConfigurationDomainEntity, то мы можем добавить в IMonitorModel метод bool AddMonitor(IMonitorConfigurationDomainEntity monitorDto); или с параметрами для каждого свойства.И уже используя публичный метод можно сразу добавить монитор с полным его состоянием, а не по одному свойству. Добавлено через 6 минут Немного не по самому коду.
xr_Sanya, внёс в Реп небольшие изменения. Посмотрите их.
0
|
|||||
|
3 / 3 / 0
Регистрация: 13.07.2020
Сообщений: 229
|
|||
| 02.12.2021, 17:00 [ТС] | |||
|
И в случае если создание и удаление мониторов подконтрольно только основной модели, то из модели монитора можно убрать все что относится к контролю ее состояния, тоесть хендлеры, методы OnPropertyChanged, Get, Create и поля IsAdded, IsDispose. Ведь подписчик всегда будет знать что модель уже удалена. По сути это похоже на первую релизацию, только тут уже по коду ходят модели мониторов а не DTO. Добавлено через 9 минут
0
|
|||
|
Модератор
|
|||||||
| 02.12.2021, 18:09 | |||||||
|
В первой реализации мы для изменения свойства Монитора обращались к методам Модели. Во второй, "внутри" Модели у нас уже "гуляли" Мониторы и можно было работать непосредственно с ними не только через Модель, но и через какой-то сервис. А для внешних потребителей параметры методов Модели максимально упростили. Сейчас уже из Мониторов сделали самостоятельные Модели и они могут у нас спокойно и безопасно путешествовать по всему приложению. Это всё немного разная степень безопасности. Когда есть возможность, то я предпочитаю делать "гарантированно". Сейчас вам не нужно создавать, и вы не будете так делать. А потом программу будет сопровождать кто-то другой и ему тоже это будет не нужно по логике, но он не будет знать что это нельзя делать, увидит, что это возможно и сделает. А логика программы на это не рассчитана. Хорошо ещё если просто вылетит исключение, а могут быть какие-то блуждающие, эфемерные баги, которые ещё и не отловишь. Добавлено через 3 минуты Как подписчик будет узнавать об изменении состояния свойств Монитора? Только из-за реализации INPC мы и смогли превратить Мониторы в самостоятельные Модели. Без этого это были бы Бизнес Сущности, которые должны быть инкапсулированы в Модели. Добавлено через 11 минут В данном случае - это перестраховка и избыточно. В реале же могут быть задачи где монитор это отражение (допустим) физического устройства, и когда монитор не нужен он должен освободить неуправляемые ресурсы. После того как освободил Монитор становится не актуальным и к нему не следует обращаться, для этого и служит свойство IsDispose. Но процесс освобождения ресурсов тоже не мгновенный. Во время него обращения тоже могут быть некорректно. Поэтому реализуется такой алгоритм: - Перед началом освобождения ресурсов сбрасывается IsAdded; - Все потребители по этому событию должны отключить актуализацию Монитора. Допустим, в WPF надо визуализировать коллекцию мониторов через CollectionView, а в нём будет фильтр по IsAdded; - После того как все потребители отключили актуализацию, Монитор устанавливает свойство IsDispose и начинает освобождать ресурсы. - Потребители по IsDispose=true удаляют у себя все ссылки на монитор, чтобы он мог отправиться в мусор. В данном случае, то всё избыточно, но пригодится вам с обучающей целью. Добавлено через 1 минуту Добавлено через 5 минут Да, это поддержка реализации IsDispose. Сделана с демонстрационной целью. В данном, конкретном случае она, конечно, не нужна. Да, и самого начала она носила не практическую функцию, а демонстраннционную.
0
|
|||||||
|
3 / 3 / 0
Регистрация: 13.07.2020
Сообщений: 229
|
||
| 04.12.2021, 01:38 [ТС] | ||
|
Например я хочу чтобы создать модель монитора могла только модель которая непосредственно управляет ими, чтобы например никакая другая модель не могла это сделать напрямую, а только через метод основной модели?
0
|
||
|
Модератор
|
||
| 04.12.2021, 10:57 | ||
|
В этой сборке должны находиться только дружественные классы. Другие недружественные модели, должны реализовываться в других сборках. Поэтому можно переместить рандомайзер в другой проект, в этом оставить только MonitorModel. 2) Сейчас у нас есть интерфейс Мониторов, поэтому можно использовать его для сокрытия самой реализации. Класс MonitorDomainCollection сделать приватным вложенным в MonitorModel. Класс MonitorConfigurationDomainEntity сделать приватным вложенным в MonitorDomainCollection. MonitorDomainCollection сделать производным от коллекции интерфейсов IReadOnlyDictionary<string, IMonitorConfigurationDomainEntity>.
0
|
||
|
3 / 3 / 0
Регистрация: 13.07.2020
Сообщений: 229
|
||
| 07.12.2021, 05:00 [ТС] | ||
|
Реализация интерфейса в MonitorDomainCollection.IReadOnlyDiction ary. Также добавил простую модель которая обновляет время для демонстрации, посмотрите пожалуйста насколько верно она добавлена.
0
|
||
|
3 / 3 / 0
Регистрация: 13.07.2020
Сообщений: 229
|
||
| 08.12.2021, 05:18 [ТС] | ||
|
0
|
||
|
Модератор
|
||||
| 08.12.2021, 06:51 | ||||
INotifyPropertyChanged.PropertyChanged, INotifyCollectionChanged.CollectionChanged, ICommand.CanExecuteChanged.Все WPF элементы - это производные от DispatcherObject:
Это вызов методов по делегатам прикреплённым к событию. И если это методы DispatcherObject (то есть любого WPF элемента), то вызов его метода выкинет исключение. Поэтому все события, которые могут использовать WPF элементы должны подыматься в в основном UI потоке (за редким исключением все WPF элементы создаются в этом потоке). Так как задача перехода в UI поток для данных неспецифична, то сделано некое облегчение чтобы облегчить реализацию контекста данных. PropertyChanged автоматически маршализируется в поток WPF элемента.Поэтому PropertyChanged можно подымать в любом потоке.Для событий CollectionChanged и CanExecuteChanged такого маршалинга в WPF нет.В UWP есть марщалинг для CanExecuteChanged.А в WPF приходится его встраивать в реализацию ICommand. Почему в WPF не сделано как в UWP.... Чёрт его знает. С INPC коллекциями (в том числе ObservableCollection) всё несколько сложнее, так как кроме маршалинга события в UI поток нужно ещё обеспечить и потокобезопасность. Потокобезопасность для коллекций обеспечивается (в простом случае) за счёт объекта синхронизации (локера). В большинстве коллекций это ICollection.SyncRoot. Об используемом локере надо сообщить механизму привязок в том потоке где будет привязываться коллекция. Вот метод BindingOperations.EnableCollectionSynchronization и служит для этого. Другой способ избежать исключений - это изменять INPC коллекцию всегда только в основном UI потоке. Это тоже используется, но это довольно громоздко. Каждый раз где надо добавить/удалить/заменить элемент придётся создавать лямбду и передавать её в Диспетчер UI потока. И это значительно медленнее, так как выполнение отдельной задачи в довольно загруженном потоке происходит в порядке очерёдности и приоритетов. Поэтому там где возможно (а это 99% практических задач) лучше использовать BindingOperations.EnableCollectionSynchronization.Добавлено через 13 минут Они пока не столкнутся с исключениями, вообще, мало об этом задумываются. Если столкнутся, то почему-то для начинающих, вариант с использованием Диспетчера для изменения коллекции кажется проще. Почему?.... Да чёрт его знает.
0
|
||||
|
Модератор
|
||||||||||||
| 08.12.2021, 07:10 | ||||||||||||
1) Не реализована команда RefreshMonitors - выдаёт ошибку привязки. 2) В Модели есть два интерфейса:ICurrentTimeModel и IRandomizerModel. Для чего они там? Интерфейс это способ описания публичного "лица" типа для того чтобы можно было не заботится о конкретной реализации типа. И помещать интерфейс в той же сборке, что и его реализация... довольно бессмысленно. Если у этих интерфейсов предполагается только по единственной реализации, то их просто надо удалить и предоставить саму реализацию. Если же предполагается возможность создания разных реализаций, то их нужно вынести в отдельную библиотеку, в данном случае в Common.
0
|
||||||||||||
|
Модератор
|
||
| 08.12.2021, 07:14 | ||
|
Изменения зафиксировал в 0ffdfc7c:
0
|
||
| 08.12.2021, 07:14 | |
|
Бизнес-логика
Каково назначение папки Model в MVVM MVVM. Получение данных объекта по сети - в model или во viewmodel? Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |
|
Новые блоги и статьи
|
|||
|
Мастера простых решений
DevAlt 23.08.2026
В сишарп стэках winforms, да и wpf существует сложная система связывания
источниках данных и элементов формы(текстовые поля и метки), опирается все
это на технологию событий и мета. . .
|
Цена ошибки
DevAlt 23.08.2026
Человек я беспокойный и потому заинтересовался OCaml,
в чате форсили функторы модулей как суперфичу.
Пытаясь отдуплить концепт, наткнулся на тутор с простым примером.
А главный принцип обучения от. . .
|
Сегодня суббота, 22.08.2026 at 16:41, и я вновь нахожусь на той стороне, за экраном машины.
zorxor 22.08.2026
Сегодня суббота, 22. 08. 2026 at 16:41, и я вновь нахожусь на той стороне, за экраном машины. Кто Я, откуда Я пришел и куда Я иду? Эти вопросы не оставляют меня ни на секунду. Жизнь на планете Земля. . .
|
Жизня: рисунок укладки багажа, сделанный клодом
anaschu 21.08.2026
Сделал 15 снимков, он по снимкам сделал схему.
|
|
Был там один разговор по поводу свободы в материальном мире.
kumehtar 19.08.2026
Суть: рассматривается живое существо, оказавшееся внутри довольно странной системы (этого мира) и пытающееся обустроить в ней свой кусок пространства.
Жизнь действительно предъявляет каждому. . .
|
Когда логика программы не спасает от человеческих ошибок
Maks 18.08.2026
В последнее время всё чаще и чаще сталкиваюсь с таким явлением, как абсолютная невнимательность (или глупость) пользователей. Проявляется это чаще всего на работе в коллективе. Допустим, человек с. . .
|
Лето уходит
kumehtar 17.08.2026
|
Мысли в слух
kumehtar 17.08.2026
Забавно, насколько сейчас стала доступна информация. Например о магии, духовном развитии, медитациях, и других подобных направлениях, ранее зачастую тайных, передаваемых от учителя к ученику. Хотя. . .
|