|
154 / 31 / 11
Регистрация: 29.10.2012
Сообщений: 397
|
||||||
WPF Установка Control.Style не триггерит set функционал у свойства класса21.05.2019, 12:59. Показов 3856. Ответов 33
Всем привет.
У меня есть класс - CoordinateView (клеточка). Он экстендит класс Grid. Также в нём есть два поля - TextBlock и Rectangle. Они добавлены в этот класс как его Children. Первый преднозначен для того чтобы показывать текст, другой нужен чтобы устанавливать цвет и толщину рамок . То есть, задача этой структуры - иметь рамки, цвет и текст. (Если есть такой control по дефолту, дайте знать, я не нашёл, и сделал вот Grid с TextBlock и Rectangle в качестве его "детей", но вопрос пока не в этом). Далее, я хочу установить свойства этой моей клеточке. Всякие разные, один из которых, например, Margin. Но хочу это делать динамично. Поэтому использую свойство Style и создаю объект из вне и добавляю в него Setter'ы того, что мне нужно. И всё работает. Всё, чётенько и классненько. Почти. В основном свойства, которые я устанавливаю относятся именно к классу Grid. Но вот есть несколько значений свойств, которые мне нужно передать "детям" (TextBlock и Rectangle), например Label и StrokeThickness. Эти два поля у меня приватные, я не хочу из вне чтобы был доступ к ним. Поэтому я создал wrapping свойства в классе своей клеточки в которых устанавливаю значения "детям". Получается вот так:
Вопрос: как сделать так, чтобы rectangle.Stroke всё-таки получал это значение, когда я устанавливаю стиль моей клеточки. Заранее спасибо!
0
|
||||||
| 21.05.2019, 12:59 | |
|
Ответы с готовыми решениями:
33
Работа свойства Bottom класса Control Выполнить команду в set свойства для свойства SelectedItem (ComboBox ) MVVM Как дополнить функционал класса из другого класса |
|
Модератор
|
||||
| 29.05.2019, 10:04 | ||||
|
В MVC всем управляет контроллер. И у него "есть право лезть" как в View, так и в Model. Взаимодействие построено по схеме: "Запросил данные от View" -> "Отправил данные в Model" -> "Получил ответ от Model" -> "Записал данные в View". Так как здесь инициация всех действий лежит на контроллере, то это удобный способ реализации WF приложений. Для них это основной паттерн. В MVVM взаимодействие построено по другой схеме. Там несколько независимы ветвей:
Так как действия в MVVM инициируются уже не контроллером, а в View, то в для связи View с VM нужен соответствующий инструмент. в WF его нет и приходится его реализовывать кастомно. Это достаточно сложно. Поэтому приложения MVVM для WF - редкость. В WPF специально для этого был создан механизм привязок. Привязки View вызывают методы VM. Именно по этому привязки возможны только к свойствам - им нужны методы set и get.Что для игры "Морской бой" должна делать Model? Представьте себе как эта Model будет работать с консолью. Модель создаёт Море и Корабли в этом Море. Какое внешние данные нужны Модели (после создания карты)? Только координаты очередного выстрела. Поэтому у Модели будет только один метод для получения данных. После получения выстрела ни View, ни VM не могут знать попал этот выстрел или нет. Полученный выстрел обрабатывается Моделью и если было попадание, то Модель изменяет свои данные - взрывает палубу Корабля и извещает об этом VM. И только обработав это извещение VM и View узнают что было попадание. View заданным образом изменяет отображение подбитой палубы. Вот теперь сами ответьте - Какое отношение стиль клетки имеет к данным Модели? Если ни какого, то зачем этот стиль нужен VM? Он абсолютно там не нужен. В общих чертах это должно быть так. В VM есть список клеток Моря. У этих клеток есть определённые возможные состояния (обычно перечисление). View выводит этот список как квадрат с заданными размерами. И каждый квадратик отображается в зависимости от своего состояния заданным в View образом. Сама же View (при клике по клетке, или через поле с координатами) отправляет в VM только координаты очередного выстрела. Вот зачем здесь передавать в VM стиль? Просто чтобы "жизнь малиной не казалась"? Стиль нужен только для настройки отображения клетки в зависимости от её состояния и никуда дальше View стиль "носа показывать" не должен. Посмотрите как в посте Суммирование элементов в 2048 я вывожу поле 4х4 и настроено отображение клеток. Как передаются данные между частями MVVM. Нужен ли для каждой View свой индивидуальный VM? По разному. Если нет других вариантов, то приходится делать разные. Но это вынужденная и редкая мера. В основном VM делается так, что она не знает какая View к ней подключена. Может WPF, а может консоль. VM - это должно быть "по барабану".
0
|
||||
|
154 / 31 / 11
Регистрация: 29.10.2012
Сообщений: 397
|
|||||||||
| 29.05.2019, 11:27 [ТС] | |||||||||
|
Как-то Вы превозносите MVVM над MVC, на мой взгляд. Про MVC говорите небрежно ("есть право лезть"). А про MVVM раза три упомянули, что только "по необходимости" общается. Так-то в MVC тоже компоненты общаются по необходимости. Но это всё неважно.
А важно вот что: Добавлено через 2 минуты Добавлено через 2 минуты Добавлено через 2 минуты Добавлено через 3 минуты Добавлено через 6 минут И ещё, Вы пишете вот это Добавлено через 5 минут
0
|
|||||||||
|
Модератор
|
|||||||||
| 29.05.2019, 13:02 | |||||||||
небрежность? Просто Контролер может напрямую сам, по собственной инициативе обращаться как к View, так и к Model.В MVVM по другому - Model не может обращаться ни к кому, VM может обращаться только к Model, View - только к VM. Все UI элементы и свойства должны быть сосредоточены в View и не покидать её. Привязка - это возможность обратиться к чьим-то методам. Так вот VM не может обращаться к методам View, то есть выражаясь по иному VM не может быть привязана к View. View привязана к VM, а VM к Model. В MVC контроллер может быть привязан как к View, так к Model. "Морской бой" - это игра для двоих. У каждого игрока есть два "Моря": одно с расстановкой своих кораблей, второе - для обстрела врага. Что это за игроки: пользователи или AI - неважно. Модель описывает одно Море. VM создаёт две модели и в зеркальном виде предоставляет доступ к ним для двух игроков. Своё Море игрок видит полностью, в море противника видит только подбитые палубы. Выстрелы от одного игрока VM передаёт в Модель противника. AI - это тоже такой же игрок. И взаимодействует с Моделью так же через VM. VM - передаёт View состояние клеточки. А как это состояние отобразить это дело уже View. Зачем VM знать о том как View отображает клеточку? Это, совершенно, излишнее знание. Если это сетевая игра, то у каждого игрока будет свой экземпляр View на локальном компе и для каждого их них будет нужен свой экземпляр VM. Это стандартное в Net взаимодействие.
0
|
|||||||||
|
Модератор
|
||
| 29.05.2019, 13:11 | ||
|
Чаще всего для простых приложений: Несколько View -> Одна VM -> Одна Model. Для "Морского боя": Если локально с AI: Две View: одна окно игрока, вторая AI без окна -> Одна VM -> Две Model. Но можно и сделать для каждого игрока по своему экземпляру VM, что бы решение было однотипным для Локальной и Сетевой игры. Тогда будет такая схема: View первого игрока или AI -> локальная VM -> Model на сервере <- локальная VM <- View второго игрока или AI
1
|
||
|
154 / 31 / 11
Регистрация: 29.10.2012
Сообщений: 397
|
|
| 29.05.2019, 14:09 [ТС] | |
|
Спасибо за ответ, Элд Хасп,
Напишу как я Вас понял, и хотел бы чтобы вы подтвердили или опровергли достоверность моего понимания. 1). View (клеточка), после того как игрок нажал на нее, тригеррит функцию в VM (через ICommand). 2). Та, в свою очередь, обращается к модели (а может и к нескольким моделям), дабы узнать статус выстрела. 3). После того, как VM получила ответ от модели, она устанавливает это значение своему свойству, на которое есть binding у view (клеточки). 4). На клеточке срабатывает конвертер и он в зависимости от этого результата (типа Enum, как Вы предложили) выбирает себе нужный стиль и устанавливает его. Если это так, то у меня всё еще есть два вопроса. Вы отвечали на один из них, но я всё равно не совсем понял, извините. 1). Когда происходит клик по клетке игроком, то, как я уже сказал выше, тригеррится соответствуюшая функция в VM. Поскольку мой вид это FrameworkElement, он не имеет координаты в себе. Он не знает, что он есть A5 или C4. Как в функции ViewModel, что срабатывает, когда кликают по клетке найти соответствующую этой клетке координату (координата у нас это модель!)? Я изначально в VM в конструктере как аргумент эту координату передаю чтобы VM потом её использовал как раз в случае клика по клетке. Но у меня такое ощущение, что Вы не имеете ввиду, что каждой клетке должен соответствовать новый экземпляр VM. Поэтому второй вопрос: 2). Как должен выглядеть VM в этом случае? Объясните пожалуйста подробно, какие свойства, поля и методы должны быть у VM. Сколько экземпляров надо создавать? И какие свойства bind'ить с клеточками или с чем там их лучше bind'ить? Простите меня за моё тугадумство, и спасибо большое Вам за терпение. Добавлено через 24 минуты И у меня ещё вопросик. Смотрите, инфы статуса выстрела для того чтобы был выбран стиль - недостаточно. Например, поле игрока, где корабли показаны, а не спрятаны отличается от того, поля, где корабли скрыты. Корабли отображаются таким образом, что... В общем, если это "моё" поле, то клетка без корабля - голубая. Если на ней корабль, то клетка зеленого цвета. Но, если поле не "моё", то даже, если там есть корабль, то клетка всё равно должна быть голубая. Означает ли это, что мне нужно будет забиндить (и предварительно создать) свойство в viewModel HideShips с чем-нибудь во view и потом использовать этот флаг в конвертере типа: если спрятать, то давай голубой, а если нет, то тащи зеленый. Так?
0
|
|
|
Модератор
|
|||||||
| 29.05.2019, 14:22 | |||||||
|
А в параметрах команды надо передавать контекст данных клеточки, То есть просто {Binding}Команда получает это контекст и из него извлекает координаты. object, а методу модели нужны int координаты, то сначала, как я уже написал, команды извлекает из параметра координаты.И что такое статус? Для выстрела это, наверное, bool - попал не попал? Так как от этого зависит право на следующий выстрел.Ответ от выстрела VM нужен для того чтобы определить кто следующий стреляет. Так как Модели это безразлично, то распределением очереди занимается VM. А вот изменение статуса Клеточки должно происходить по событийной схеме. Модель изменяет статус Клеточки, Клеточка через событие извещает своих подписчиков об изменении. Так как View является подписчиком INPC, то View обрабатывает изменение статуса. Здесь должно хватить возможностей стиля с триггерами. Клеточка ОТОБРАЖАЕТ данные, соответствующего типа, допустим, Cell. У этого типа есть свойства необходимые для его идентификации и состояния, в том числе строка, колонка, статус и др.Посмотрите для примера класс Cell здесь Суммирование элементов в 2048 Когда создаётся команда её будет передаваться параметр, если параметр будет привязан к контексту данных {Binding}, то в методе обрабатывающем команду в параметре будет объект Cell и из него можно будет получить нужные данные.Надо сначала спроектировать приложение. Потом создать Model и интерфейс для View. И VM будет реализовывать этот интерфейс. То что сейчас очевидно для реализации с двумя VM это:
Возможно нужны будут для более красивой визуализации и информативности
Дальше надо смотреть по ходу реализации
1
|
|||||||
|
Модератор
|
||
| 29.05.2019, 14:29 | ||
|
Это возможность для хака. В варианте с двумя VM Модель отдаёт разные данные в разные VM. Для VM Cell на Sea противника до попадания - это пустой контент (свойство Content). После попадания в Content Model записывает Deck с состоянием Destroyed.
0
|
||
|
Модератор
|
|
| 29.05.2019, 14:35 | |
|
Pro100Tom, у меня уже путаница в голове от предполагаемых различных вариаций.
Для таких подробностей нужно уже проектировать приложение и решать вопросы уже в конкретной реализации, а то только путаницу разведём.
0
|
|
|
154 / 31 / 11
Регистрация: 29.10.2012
Сообщений: 397
|
||
| 29.05.2019, 15:57 [ТС] | ||
|
Всё, я вроде бы всё понял наконец-то. 2048 прост спасло мне жизнь. Я теперь врубился, что значит "отображение данных" в данном контексте.
У меня есть ещё один вопрос и скорее всего после этого я отстану. Как я понимаю, изменения вида происходят по триггерам, как вы реализовали в 2048. А также написали выше следующее: Смотрите, моя модель координаты не имеет свойств кроме как row и column. В ней нет свойста WasChecked или HasShip, потому что как бы и не надо. Могу ли я забиндить некоторые свойства стиля моей клеточки триггером со свойством модели корабля? Например, у меня есть корабль и его свойство IsSunk. И триггер на background клетки поставить, что мол поменяй цвет на чёрный, если корабль потонул? Я задаю этот вопрос потому что я понимаю что в изоляции клетку можно забиндить с чем угодно, но в этом контексте она уже забиндина с моделью Cell. Или если биндинг уже есть, то свойство забиндить с чем-то другим уже нельзя и в таком случае в модели Cell мне придётся впихивать свойства WasChecked, HasShip, IsShipSunk?
0
|
||
|
Модератор
|
|||
| 29.05.2019, 16:04 | |||
Cell и корабль.Моей проекте моей Model тип Cell имел свойство Content в котором мог содержать палубу корабля Deck. Поэтому все привязки создавались без проблем.А у Вас как связаны Cell и корабль?
0
|
|||
|
154 / 31 / 11
Регистрация: 29.10.2012
Сообщений: 397
|
|
| 29.05.2019, 16:10 [ТС] | |
|
У меня корабль имеет список of Cells. Когда мой VM будет проверять статус выстрела (мимо/ранил/убил), то в сервисе я логику описал так, что мы берем объект моря, берем в нём корабли и смотрим, есть ли корабль, в котором есть эта Cell. Если да, то надо еще проверить ранен ли корабль или уже убит, для этого у него реализовано свойство (или функция, не помню) которое возвращает флаг - мол, да, убит. Свойство "убит" важно, потому что я хочу чтобы, раненые корабли отображались оранжевым цветом, а вот потонувшие - меняли бы свой цвет (всех соответствующих креточек) на черный. А свойство "убит" должно находиться именно в модели класс Ship, а не Cell, имхо.
0
|
|
|
Модератор
|
|
| 29.05.2019, 16:50 | |
|
Pro100Tom, Из-за начальной неправильно проектирования у Вас неверно распределены функции для VM и Model.
То что Вы описывает - может находиться в Model. Так как она обрабатывает свои данные удобным для себя образом не взирая на то как эти данные потом будут отображаться. Функция же VM - это преобразование данных Model в удобный для View вид. В данном случае, View у Вас отображает клеточки Cell. Этот тип должен предоставлять все данные необходимые его для отображения. Так Cell у Вас - это класс Model и не содержит всех требуемых свойств, то значит VM должна объявить свой тип для Cell и переносить данные в него из Model.Cell. Но это общий подход. В таком маленьком приложении как у Вас. Когда всё в одних руках, то проще изменить Model. На мой взгляд, Вы из-за недостатка опыта неверно спроектировали приложение. Поэтому у Вас неверно реализована Model - если она есть, вообще. Вы, по всей видимости, начали реализацию с View - отсюда и множество нестыковок.
0
|
|
|
154 / 31 / 11
Регистрация: 29.10.2012
Сообщений: 397
|
|
| 29.05.2019, 17:03 [ТС] | |
|
Блин, вот не соглашусь с Вами. Cell - это клетка. Её задача хранить координаты. А Ship - это объект который мы ищем, играя в игру. Как тут можно смешать клетку и корабль в один винегрет-то? У меня корабли есть различных форм (нетолько прямые), я описал матрицу их поворота и отражения, описал логику расставления. Я не согласен с тем, что только потому что у меня проблема с биндингом, я не должен создавать ship как отдельный класс. Не хочу я менять модель клетки. Клетка не должна знать ничего о кораблях. Пройдёт время, я захочу добавить мины в игру, и что, мне придётся тогда менять снова класс клетки?
Я выбрал WPF потому что мне нравится визуализация. На биндинги мне плевать. Если использование WPF подразумевает использование биндингов - здорово, у меня есть повод изучить это и реализовать код используя эти биндинги. Но, если структура с биндингами заставялет меня смешивать два класса в одну кашу, извините - к чёрту биндинги. Я понимаю, что WPF не для морского боя создан. Так что, ещё разочек, повторю вопрос. Есть ли возможность создать Background свойство клетки со свойством корабля, если клетка уже связана с моделью Cell? Если нельзя, то норм ли имплементация где я в своей ViewModel создаю свойство, которое будет "следить" за свойством корабля IsSunk, и это свойство (класса ViewModel) будет забиндино с Background свойством моей клеточки (и то тут будет проблема одна связанная с выбором кол-ва экземпляров класса VM)? Если ответ нет, то стоит ли забить на биндинги и просто удалить гланды через задницу?
0
|
|
|
Модератор
|
||||||
| 29.05.2019, 18:16 | ||||||
|
А типы для View имеют совсем иное назначение. Эти типы предназначены для ОТОБРАЖЕНИЯ. И если не хотите менять MODEL, то это Ваше видение - делайте так. Но тогда надо из типов Модели делать преобразование в типы View - это одна из основных функций VM. VM получает от Модели Cell и Ship и преобразует их уже в удобный для View вид - это тип клетки (назовите его - CellView) в котором содержится вся необходимая для отображения информация. Допустим Model - это WEB сервер. И он обменивается с VM текстовыми сообщениями в формате JSON. И что теперь этот JSON тоже WPF должен отображать? Нет! VM преобразует полученные JSON в типы для View. Это то для чего и предназначена VM. У Вас вся путаница из-за того что большая часть функций Модели возложена на VM. И в результате VM не делает того собственно для чего она предназначена. VM, если не нужно преобразование, может напрямую передавать данные Модели прямо в её типах. Но такое возможно только в локальных приложениях. В общем же случае, перед передачей данных, VM их конвертирует в удобную для View форму. Эти инструменты появились не на пустом месте - за ними десятки лет опыта миллионов программистов. Если они для чего-то не подходят, то это, в первую очередь, вопрос к себе А на верном ли я пути?.Конечно, как и любое творение рук человеческих, они не совершены. Но прежде чем пытаться их изменять или использовать их не по назначению, надо научиться их использовать тем образом для которого они предназначены. И уже потом делать выводы.
1
|
||||||
| 29.05.2019, 18:16 | |
|
Помогаю со студенческими работами здесь
34
Можно ли изменить тип возвращаемого значения через свойства? Где автоматические свойства сохраняют значения? Свойства set get
Биндинг свойства контрола к одной из переменных свойства класса Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |
|
Новые блоги и статьи
|
|||
|
Модель заражения группы наркоманов
alhaos 17.04.2026
Условия задачи сформулированы тут
Суть:
- Группа наркоманов из 10 человек.
- Только один инфицирован ВИЧ.
- Колются одной иглой.
- Колются раз в день.
- Колются последовательно через. . .
|
Мысли в слух. Про "навсегда".
kumehtar 16.04.2026
Подумалось тут, что наверное очень глупо использовать во всяких своих установках понятие "навсегда". Это очень сильное понятие, и я только начинаю понимать край его смысла, не смотря на то что давно. . .
|
My Business CRM
MaGz GoLd 16.04.2026
Всем привет, недавно возникла потребность создать CRM, для личных нужд. Собственно программа предоставляет из себя базу данных клиентов, в которой можно фиксировать звонки, стадии сделки, а также. . .
|
Знаешь почему 90% людей редко бывают счастливыми?
kumehtar 14.04.2026
Потому что они ждут. Ждут выходных, ждут отпуска, ждут удачного момента. . .
а удачный момент так и не приходит.
|
|
Фиксация колонок в отчете СКД
Maks 14.04.2026
Фиксация колонок в СКД отчета типа Таблица.
Задача: зафиксировать три левых колонки в отчете.
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
/ / . . .
|
Настройки VS Code
Loafer 13.04.2026
{
"cmake. configureOnOpen": false,
"diffEditor. ignoreTrimWhitespace": true,
"editor. guides. bracketPairs": "active",
"extensions. ignoreRecommendations": true,
. . .
|
Оптимизация кода на разграничение прав доступа к элементам формы
Maks 13.04.2026
Алгоритм из решения ниже реализован на нетиповом документе, разработанного в конфигурации КА2.
Задачи, как таковой, поставлено не было, проделанное ниже исключительно моя инициатива.
Было так:. . .
|
Контроль заполнения и очистка дат в зависимости от значения перечислений
Maks 12.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "ПланированиеПерсонала", разработанного в конфигурации КА2.
Задача: реализовать контроль корректности заполнения дат назначения. . .
|