С Новым годом! Форум программистов, компьютерный форум, киберфорум
C#: WPF, UWP и Silverlight
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.72/18: Рейтинг темы: голосов - 18, средняя оценка - 4.72
154 / 31 / 11
Регистрация: 29.10.2012
Сообщений: 397
1
WPF

Установка Control.Style не триггерит set функционал у свойства класса

21.05.2019, 12:59. Показов 3278. Ответов 33

Author24 — интернет-сервис помощи студентам
Всем привет.

У меня есть класс - CoordinateView (клеточка). Он экстендит класс Grid. Также в нём есть два поля - TextBlock и Rectangle. Они добавлены в этот класс как его Children. Первый преднозначен для того чтобы показывать текст, другой нужен чтобы устанавливать цвет и толщину рамок . То есть, задача этой структуры - иметь рамки, цвет и текст. (Если есть такой control по дефолту, дайте знать, я не нашёл, и сделал вот Grid с TextBlock и Rectangle в качестве его "детей", но вопрос пока не в этом).

Далее, я хочу установить свойства этой моей клеточке. Всякие разные, один из которых, например, Margin. Но хочу это делать динамично. Поэтому использую свойство Style и создаю объект из вне и добавляю в него Setter'ы того, что мне нужно. И всё работает. Всё, чётенько и классненько. Почти.

В основном свойства, которые я устанавливаю относятся именно к классу Grid. Но вот есть несколько значений свойств, которые мне нужно передать "детям" (TextBlock и Rectangle), например Label и StrokeThickness. Эти два поля у меня приватные, я не хочу из вне чтобы был доступ к ним. Поэтому я создал wrapping свойства в классе своей клеточки в которых устанавливаю значения "детям". Получается вот так:
C#
1
2
3
4
5
public Brush Stroke
{
    get => rectangle.Stroke;
    set => rectangle.Stroke = value;
}
Проблема заключается в том, что, когда я устанавливаю значения этим своим свойствам (конечно, я создал DependencyProperty к каждому из этих свойств чтобы Style.Setter мог им пользоваться), то значение не передаётся дальше в rectangle.Stroke. Я установил breakpoint на строке set => ... и когда программа проходит код coordinateView.Style = style, то код не останавливается на этом brealpoint'е. Мне это не нравится, потому что значение Stroke моей клеточки устанавливается (я вижу в debugging окне изменение значения), а вот set => ... не тригеррится и поэтому rectangle.Stroke не получает нового значения.

Вопрос: как сделать так, чтобы rectangle.Stroke всё-таки получал это значение, когда я устанавливаю стиль моей клеточки.


Заранее спасибо!
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
21.05.2019, 12:59
Ответы с готовыми решениями:

Работа свойства Bottom класса Control
Объясните пожалуйста, как с помощью свойства Bottom (которое получает расстояние (в пикселях) между...

Выполнить команду в set свойства для свойства SelectedItem (ComboBox ) MVVM
Хай Коротко: при каждом выборе элемента из ComboBox нужно выполнять команду, для которой в...

Как дополнить функционал класса из другого класса
Вот допустим, написал я класс TMatrix (матрица), можно добавлять строки, столбцы, есть capacity и...

Свойства get и set
Можно ли изменить тип возвращаемого значения через свойства? Или же свойства не приспособлены к...

33
Модератор
Эксперт .NET
15846 / 10994 / 2852
Регистрация: 21.04.2018
Сообщений: 32,253
Записей в блоге: 2
29.05.2019, 10:04 21
Author24 — интернет-сервис помощи студентам
Цитата Сообщение от Pro100Tom Посмотреть сообщение
MVC, (теперь и чуть-чуть MVVM) мне знакомы
Хотя MVVM, на сколько помню, "вырос" из MVC между ними есть разница.
В MVC всем управляет контроллер. И у него "есть право лезть" как в View, так и в Model. Взаимодействие построено по схеме: "Запросил данные от View" -> "Отправил данные в Model" -> "Получил ответ от Model" -> "Записал данные в View".
Так как здесь инициация всех действий лежит на контроллере, то это удобный способ реализации WF приложений. Для них это основной паттерн.

В MVVM взаимодействие построено по другой схеме. Там несколько независимы ветвей:
  • "View отправляет данные в VM" -> "VM их обрабатывает и, при необходимости, отправляет в Model"
  • "В VM изменяются данные предназначенные для связи с View" -> "VM через INPC извещает об изменении данных View" -> "View, при необходимости, получает изменённые данные от VM" -> "VM, при необходимости, получает данные от Model"
  • "В Model изменяются данные предназначенные для пользователей" -> "Model генерирует событие об изменении данных (можно использовать тоже INPC)" -> "VM обрабатывает событие и изменяет свои данные и/или посылает извещение в View"
Графически я всё это отобразил и объяснил здесь INPC (INotifyPropertyChanged) и получение данных из Модели [WPF, Элд Хасп]

Так как действия в MVVM инициируются уже не контроллером, а в View, то в для связи View с VM нужен соответствующий инструмент. в WF его нет и приходится его реализовывать кастомно. Это достаточно сложно. Поэтому приложения MVVM для WF - редкость.

В WPF специально для этого был создан механизм привязок. Привязки View вызывают методы VM. Именно по этому привязки возможны только к свойствам - им нужны методы set и get.

Цитата Сообщение от Pro100Tom Посмотреть сообщение
Правильно ли я понимаю, что для каждого вида нужен свой viewModel? Если так, то я не вижу ошибки в своей архитектуре. Мы создаём консоль, создаем viewModel для неё и вызываем ту же модель, которая возвращает "мимо/ранил/убил" и viewModel уже решает что там надо возвращать окну.
Какие данные View должна отправлять в VM? Это те данные которые после обработки должны быть отправлены в Model. Те данные которые необходимы для взаимодействия внутри View должны обрабатываться в ней самой. Очень часто для этого используются WPF конвертеры.

Что для игры "Морской бой" должна делать 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 - это должно быть "по барабану".

Цитата Сообщение от Pro100Tom Посмотреть сообщение
За литературу спасибо, я обязательно всё изучу.
Это не литература. Это темы с форума где я старался объяснить WPF и MVVM.
0
154 / 31 / 11
Регистрация: 29.10.2012
Сообщений: 397
29.05.2019, 11:27  [ТС] 22
Как-то Вы превозносите MVVM над MVC, на мой взгляд. Про MVC говорите небрежно ("есть право лезть"). А про MVVM раза три упомянули, что только "по необходимости" общается. Так-то в MVC тоже компоненты общаются по необходимости. Но это всё неважно.

А важно вот что:
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Какие данные View должна отправлять в VM? Это те данные которые после обработки должны быть отправлены в Model. Те данные которые необходимы для взаимодействия внутри View должны обрабатываться в ней самой. Очень часто для этого используются WPF конвертеры.
View никаких данных не отправляет. Я ни разу не сказал, что view (клеточка) должна отправлять данные классу viewModel. Мой класс viewModel имеет поле координаты и еще он привязан к моему view (клеточке). Когда на клеточку нажимают, срабатывает команда и выполняется функция в моей viewModel. Там, в этой функции, мы используем модель и проверяем есть ли корабль на этой координате; если есть, то проверяем убит ли он (помимо того, что он ранен). Я думал, о конвертерах, но решил их не использовать по той причине, что в данном случае будет не просто конвертация, а... Так, меня по ходу осенило, пока я писал это. Ведь мы действительно конвертируем мимо/ранил/убил в цвет... Может быть и действительно стоит использовать конвертер. Но всё равно я должен в своём viewModel описать логику получаения результата (мимо/ранил/убил). Так? Я ведь не могу привязать свой view (клеточку) к модели корабля.

Добавлено через 2 минуты
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Полученный выстрел обрабатывается Моделью и если было попадание, то Модель изменяет свои данные - взрывает палубу Корабля и извещает об этом VM. И только обработав это извещение VM и View узнают что было попадание. View заданным образом изменяет отображение подбитой палубы.
Как это сделать? Модель должна быть привязяна к view? Я читал в MSDN, что обычно привязывают ViewModel с V, и реже Model с View. Если я привяжу view к модели, то как у меня будет работать viewModel? Я ведь не могу привязать мой view сразу и к viewModel и к модели.

Добавлено через 2 минуты
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Поэтому у Модели будет только один метод для получения данных. После получения выстрела ни View, ни VM не могут знать попал этот выстрел или нет.
Откуда (view или viewModel) должен вызываться метод выстрела? Я думаю, что из viewModel.

Добавлено через 2 минуты
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Вот теперь сами ответьте - Какое отношение стиль клетки имеет к данным Модели? Если ни какого, то зачем этот стиль нужен VM? Он абсолютно там не нужен.
Так мой стиль не имеет отношения к модели. Я его добавил в viewModel как Dependency Injection, чтобы потом возвращать, когда нужно.

Добавлено через 3 минуты
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Сама же View (при клике по клетке, или через поле с координатами) отправляет в VM только координаты очередного выстрела.
Откуда у view данные о координате? Мой view имеет только стиль. Но у меня есть модель координаты, и класс battlefield (тоже модель) который хранит в себе этот список координат. Именно модель, а не view или viewModel, потому что AI будет стрелять в игрока используя модель, а не клеточки на экране.

Добавлено через 6 минут
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Вот зачем здесь передавать в VM стиль?
Я в VM из view не передаю стиль. Я его передал один раз в конструктере при создании своего viewModel, чтобы он этот стиль возвращал клеточке.

И ещё, Вы пишете вот это
Цитата Сообщение от Элд Хасп Посмотреть сообщение
В VM есть список клеток Моря. У этих клеток есть определённые возможные состояния (обычно перечисление).
Означает ли это, что нужен только один экземпляр класса viewModel для каждого экземпляра моей клеточки (view)? Мне казалось, что кол-во экземпляров viewModel должно соответствовать кол-ву экземпляров клеточек, иначе как привязка будет работать... Но если я прав, то зачем в VM иметь целый список клеток Моря? То есть у мены будет сто экземпляров viewModel, в каждом из которых будет по сто клеток? Кстати, о каких клетках идёт речь, о виде или о моделе?

Добавлено через 5 минут
Цитата Сообщение от Pro100Tom Посмотреть сообщение
Как это сделать? Модель должна быть привязяна к view? Я читал в MSDN, что обычно привязывают ViewModel с V, и реже Model с View. Если я привяжу view к модели, то как у меня будет работать viewModel? Я ведь не могу привязать мой view сразу и к viewModel и к модели.
Или вы имеете ввиду поднять эвент в модели и подписаться к нему из viewModel?
0
Модератор
Эксперт .NET
15846 / 10994 / 2852
Регистрация: 21.04.2018
Сообщений: 32,253
Записей в блоге: 2
29.05.2019, 13:02 23
Цитата Сообщение от Pro100Tom Посмотреть сообщение
Про MVC говорите небрежно ("есть право лезть")
При чём здесь небрежность? Просто Контролер может напрямую сам, по собственной инициативе обращаться как к View, так и к Model.
В MVVM по другому - Model не может обращаться ни к кому, VM может обращаться только к Model, View - только к VM.
Все UI элементы и свойства должны быть сосредоточены в View и не покидать её.

Цитата Сообщение от Pro100Tom Посмотреть сообщение
Мой класс viewModel имеет поле координаты и еще он привязан к моему view (клеточке)
Цитата Сообщение от Pro100Tom Посмотреть сообщение
Я читал в MSDN, что обычно привязывают ViewModel с V, и реже Model с View.
Вы что-то не так поняли.
Привязка - это возможность обратиться к чьим-то методам.
Так вот VM не может обращаться к методам View, то есть выражаясь по иному VM не может быть привязана к View.
View привязана к VM, а VM к Model.

В MVC контроллер может быть привязан как к View, так к Model.

Цитата Сообщение от Pro100Tom Посмотреть сообщение
Откуда (view или viewModel) должен вызываться метод выстрела? Я думаю, что из viewModel.
Model это без разницы. А в плане MVVM - все действия инициируются пользователем, то есть они в приложение поступают через View. View в ответ на действие пользователя может вызвать метод VM, а та может вызвать метод Model.

Цитата Сообщение от Pro100Tom Посмотреть сообщение
Откуда у view данные о координате? Мой view имеет только стиль. Но у меня есть модель координаты, и класс battlefield (тоже модель) который хранит в себе этот список координат. Именно модель, а не view или viewModel, потому что AI будет стрелять в игрока используя модель, а не клеточки на экране.
Здесь у нас опять какое-то недопонимание друг друга.
"Морской бой" - это игра для двоих.
У каждого игрока есть два "Моря": одно с расстановкой своих кораблей, второе - для обстрела врага.
Что это за игроки: пользователи или AI - неважно.
Модель описывает одно Море.
VM создаёт две модели и в зеркальном виде предоставляет доступ к ним для двух игроков.
Своё Море игрок видит полностью, в море противника видит только подбитые палубы.

Выстрелы от одного игрока VM передаёт в Модель противника.

AI - это тоже такой же игрок. И взаимодействует с Моделью так же через VM.

Цитата Сообщение от Pro100Tom Посмотреть сообщение
Я в VM из view не передаю стиль. Я его передал один раз в конструктере при создании своего viewModel, чтобы он этот стиль возвращал клеточке.
А зачем?
VM - передаёт View состояние клеточки. А как это состояние отобразить это дело уже View. Зачем VM знать о том как View отображает клеточку? Это, совершенно, излишнее знание.

Цитата Сообщение от Pro100Tom Посмотреть сообщение
Означает ли это, что нужен только один экземпляр класса viewModel для каждого экземпляра моей клеточки (view)?
Если это локальная игра против AI, то модель может быть одна. Она будет предоставлять данные обоим игрокам.
Если это сетевая игра, то у каждого игрока будет свой экземпляр View на локальном компе и для каждого их них будет нужен свой экземпляр VM.

Цитата Сообщение от Pro100Tom Посмотреть сообщение
Или вы имеете ввиду поднять эвент в модели и подписаться к нему из viewModel?
При изменении данных объект уведомляет об этом своих подписчиков через событие.
Это стандартное в Net взаимодействие.
0
Модератор
Эксперт .NET
15846 / 10994 / 2852
Регистрация: 21.04.2018
Сообщений: 32,253
Записей в блоге: 2
29.05.2019, 13:11 24
Цитата Сообщение от Pro100Tom Посмотреть сообщение
Мне казалось, что кол-во экземпляров viewModel должно соответствовать кол-ву экземпляров клеточек, иначе как привязка будет работать...
Нет.
Чаще всего для простых приложений: Несколько 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  [ТС] 25
Спасибо за ответ, Элд Хасп,

Напишу как я Вас понял, и хотел бы чтобы вы подтвердили или опровергли достоверность моего понимания.

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
Модератор
Эксперт .NET
15846 / 10994 / 2852
Регистрация: 21.04.2018
Сообщений: 32,253
Записей в блоге: 2
29.05.2019, 14:22 26
Цитата Сообщение от Pro100Tom Посмотреть сообщение
1). View (клеточка), после того как игрок нажал на нее, тригеррит функцию в VM (через ICommand).
Если клеточка это кнопка, то - да.
А в параметрах команды надо передавать контекст данных клеточки, То есть просто {Binding}
Команда получает это контекст и из него извлекает координаты.

Цитата Сообщение от Pro100Tom Посмотреть сообщение
2). Та, в свою очередь, обращается к модели (а может и к нескольким моделям), дабы узнать статус выстрела.
Так как команда в параметрах получает object, а методу модели нужны int координаты, то сначала, как я уже написал, команды извлекает из параметра координаты.

И что такое статус? Для выстрела это, наверное, bool - попал не попал? Так как от этого зависит право на следующий выстрел.

Цитата Сообщение от Pro100Tom Посмотреть сообщение
3). После того, как VM получила ответ от модели, она устанавливает это значение своему свойству, на которое есть binding у view (клеточки).
Нет!
Ответ от выстрела VM нужен для того чтобы определить кто следующий стреляет. Так как Модели это безразлично, то распределением очереди занимается VM.

А вот изменение статуса Клеточки должно происходить по событийной схеме. Модель изменяет статус Клеточки, Клеточка через событие извещает своих подписчиков об изменении. Так как View является подписчиком INPC, то View обрабатывает изменение статуса.

Цитата Сообщение от Pro100Tom Посмотреть сообщение
4). На клеточке срабатывает конвертер и он в зависимости от этого результата (типа Enum, как Вы предложили) выбирает себе нужный стиль и устанавливает его.
Конвертер здесь, наверное, не пригодится.
Здесь должно хватить возможностей стиля с триггерами.


Цитата Сообщение от Pro100Tom Посмотреть сообщение
1). Когда происходит клик по клетке игроком, то, как я уже сказал выше, тригеррится соответствуюшая функция в VM. Поскольку мой вид это FrameworkElement, он не имеет координаты в себе. Он не знает, что он есть A5 или C4. Как в функции ViewModel, что срабатывает, когда кликают по клетке найти соответствующую этой клетке координату (координата у нас это модель!)? Я изначально в VM в конструктере как аргумент эту координату передаю чтобы VM потом её использовал как раз в случае клика по клетке. Но у меня такое ощущение, что Вы не имеете ввиду, что каждой клетке должен соответствовать новый экземпляр VM. Поэтому второй вопрос:
View - это ОТОБРАЖЕНИЕ данных.
Клеточка ОТОБРАЖАЕТ данные, соответствующего типа, допустим, Cell. У этого типа есть свойства необходимые для его идентификации и состояния, в том числе строка, колонка, статус и др.
Посмотрите для примера класс Cell здесь Суммирование элементов в 2048

Когда создаётся команда её будет передаваться параметр, если параметр будет привязан к контексту данных {Binding}, то в методе обрабатывающем команду в параметре будет объект Cell и из него можно будет получить нужные данные.

Цитата Сообщение от Pro100Tom Посмотреть сообщение
2). Как должен выглядеть VM в этом случае? Объясните пожалуйста подробно, какие свойства, поля и методы должны быть у VM. Сколько экземпляров надо создавать? И какие свойства bind'ить с клеточками или с чем там их лучше bind'ить?
Так с ходу сказать невозможно.
Надо сначала спроектировать приложение. Потом создать Model и интерфейс для View. И VM будет реализовывать этот интерфейс.

То что сейчас очевидно для реализации с двумя VM это:
  • Размерность Моря (Sea)
  • Список клеточек (Cell) для своего моря
  • Список Cell для моря противника
  • Свойство разрешающее выстрел
  • Команда принимающая выстрел

Возможно нужны будут для более красивой визуализации и информативности
  • Списки (свой и противника) кораблей (Ship)
  • Списки палуб (Deck)
  • Списки Cell по которым уже были сделаны выстрелы
  • Количества кораблей на плаву
  • Количества палуб на плаву
  • Количество сделанных выстрелов
  • Процент попадания

Дальше надо смотреть по ходу реализации
1
Модератор
Эксперт .NET
15846 / 10994 / 2852
Регистрация: 21.04.2018
Сообщений: 32,253
Записей в блоге: 2
29.05.2019, 14:29 27
Цитата Сообщение от Pro100Tom Посмотреть сообщение
И у меня ещё вопросик. Смотрите, инфы статуса выстрела для того чтобы был выбран стиль - недостаточно. Например, поле игрока, где корабли показаны, а не спрятаны отличается от того, поля, где корабли скрыты. Корабли отображаются таким образом, что... В общем, если это "моё" поле, то клетка без корабля - голубая. Если на ней корабль, то клетка зеленого цвета. Но, если поле не "моё", то даже, если там есть корабль, то клетка всё равно должна быть голубая. Означает ли это, что мне нужно будет забиндить (и предварительно создать) свойство в viewModel HideShips с чем-нибудь во view и потом использовать этот флаг в конвертере типа: если спрятать, то давай голубой, а если нет, то тащи зеленый. Так?
Нет!
Это возможность для хака.
В варианте с двумя VM Модель отдаёт разные данные в разные VM.
Для VM Cell на Sea противника до попадания - это пустой контент (свойство Content). После попадания в Content Model записывает Deck с состоянием Destroyed.
0
Модератор
Эксперт .NET
15846 / 10994 / 2852
Регистрация: 21.04.2018
Сообщений: 32,253
Записей в блоге: 2
29.05.2019, 14:35 28
Pro100Tom, у меня уже путаница в голове от предполагаемых различных вариаций.
Для таких подробностей нужно уже проектировать приложение и решать вопросы уже в конкретной реализации, а то только путаницу разведём.
0
154 / 31 / 11
Регистрация: 29.10.2012
Сообщений: 397
29.05.2019, 15:57  [ТС] 29
Всё, я вроде бы всё понял наконец-то. 2048 прост спасло мне жизнь. Я теперь врубился, что значит "отображение данных" в данном контексте.

У меня есть ещё один вопрос и скорее всего после этого я отстану.
Как я понимаю, изменения вида происходят по триггерам, как вы реализовали в 2048. А также написали выше следующее:
Цитата Сообщение от Элд Хасп Посмотреть сообщение
При изменении данных объект уведомляет об этом своих подписчиков через событие.
Может ли (а точнее допустимо ли в конструкции MVVM) view быть подписчиком модели?

Смотрите, моя модель координаты не имеет свойств кроме как row и column. В ней нет свойста WasChecked или HasShip, потому что как бы и не надо. Могу ли я забиндить некоторые свойства стиля моей клеточки триггером со свойством модели корабля? Например, у меня есть корабль и его свойство IsSunk. И триггер на background клетки поставить, что мол поменяй цвет на чёрный, если корабль потонул? Я задаю этот вопрос потому что я понимаю что в изоляции клетку можно забиндить с чем угодно, но в этом контексте она уже забиндина с моделью Cell. Или если биндинг уже есть, то свойство забиндить с чем-то другим уже нельзя и в таком случае в модели Cell мне придётся впихивать свойства WasChecked, HasShip, IsShipSunk?
0
Модератор
Эксперт .NET
15846 / 10994 / 2852
Регистрация: 21.04.2018
Сообщений: 32,253
Записей в блоге: 2
29.05.2019, 16:04 30
Цитата Сообщение от Pro100Tom Посмотреть сообщение
у меня есть корабль и его свойство IsSunk
Цитата Сообщение от Pro100Tom Посмотреть сообщение
о в этом контексте она уже забиндина с моделью Cell
Не совсем понятно как у Вас соотносятся Cell и корабль.
Моей проекте моей Model тип Cell имел свойство Content в котором мог содержать палубу корабля Deck. Поэтому все привязки создавались без проблем.
А у Вас как связаны Cell и корабль?
0
154 / 31 / 11
Регистрация: 29.10.2012
Сообщений: 397
29.05.2019, 16:10  [ТС] 31
У меня корабль имеет список of Cells. Когда мой VM будет проверять статус выстрела (мимо/ранил/убил), то в сервисе я логику описал так, что мы берем объект моря, берем в нём корабли и смотрим, есть ли корабль, в котором есть эта Cell. Если да, то надо еще проверить ранен ли корабль или уже убит, для этого у него реализовано свойство (или функция, не помню) которое возвращает флаг - мол, да, убит. Свойство "убит" важно, потому что я хочу чтобы, раненые корабли отображались оранжевым цветом, а вот потонувшие - меняли бы свой цвет (всех соответствующих креточек) на черный. А свойство "убит" должно находиться именно в модели класс Ship, а не Cell, имхо.
0
Модератор
Эксперт .NET
15846 / 10994 / 2852
Регистрация: 21.04.2018
Сообщений: 32,253
Записей в блоге: 2
29.05.2019, 16:50 32
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  [ТС] 33
Блин, вот не соглашусь с Вами. Cell - это клетка. Её задача хранить координаты. А Ship - это объект который мы ищем, играя в игру. Как тут можно смешать клетку и корабль в один винегрет-то? У меня корабли есть различных форм (нетолько прямые), я описал матрицу их поворота и отражения, описал логику расставления. Я не согласен с тем, что только потому что у меня проблема с биндингом, я не должен создавать ship как отдельный класс. Не хочу я менять модель клетки. Клетка не должна знать ничего о кораблях. Пройдёт время, я захочу добавить мины в игру, и что, мне придётся тогда менять снова класс клетки?

Я выбрал WPF потому что мне нравится визуализация. На биндинги мне плевать. Если использование WPF подразумевает использование биндингов - здорово, у меня есть повод изучить это и реализовать код используя эти биндинги. Но, если структура с биндингами заставялет меня смешивать два класса в одну кашу, извините - к чёрту биндинги. Я понимаю, что WPF не для морского боя создан.

Так что, ещё разочек, повторю вопрос. Есть ли возможность создать Background свойство клетки со свойством корабля, если клетка уже связана с моделью Cell? Если нельзя, то норм ли имплементация где я в своей ViewModel создаю свойство, которое будет "следить" за свойством корабля IsSunk, и это свойство (класса ViewModel) будет забиндино с Background свойством моей клеточки (и то тут будет проблема одна связанная с выбором кол-ва экземпляров класса VM)? Если ответ нет, то стоит ли забить на биндинги и просто удалить гланды через задницу?
0
Модератор
Эксперт .NET
15846 / 10994 / 2852
Регистрация: 21.04.2018
Сообщений: 32,253
Записей в блоге: 2
29.05.2019, 18:16 34
Цитата Сообщение от Pro100Tom Посмотреть сообщение
А Ship - это объект который мы ищем, играя в игру. Как тут можно смешать клетку и корабль в один винегрет-то? У меня корабли есть различных форм (нетолько прямые), я описал матрицу их поворота и отражения, описал логику расставления. Я не согласен с тем, что только потому что у меня проблема с биндингом, я не должен создавать ship как отдельный класс. Не хочу я менять модель клетки. Клетка не должна знать ничего о кораблях. Пройдёт время, я захочу добавить мины в игру, и что, мне придётся тогда менять снова класс клетки?
Вы описываете поведение MODEL.
А типы для View имеют совсем иное назначение. Эти типы предназначены для ОТОБРАЖЕНИЯ.
И если не хотите менять MODEL, то это Ваше видение - делайте так.
Но тогда надо из типов Модели делать преобразование в типы View - это одна из основных функций VM.
VM получает от Модели Cell и Ship и преобразует их уже в удобный для View вид - это тип клетки (назовите его - CellView) в котором содержится вся необходимая для отображения информация.

Цитата Сообщение от Pro100Tom Посмотреть сообщение
Я выбрал WPF потому что мне нравится визуализация. На биндинги мне плевать. Если использование WPF подразумевает использование биндингов - здорово, у меня есть повод изучить это и реализовать код используя эти биндинги. Но, если структура с биндингами заставялет меня смешивать два класса в одну кашу, извините - к чёрту биндинги. Я понимаю, что WPF не для морского боя создан.
Это функция VM.
Допустим Model - это WEB сервер. И он обменивается с VM текстовыми сообщениями в формате JSON.
И что теперь этот JSON тоже WPF должен отображать?
Нет! VM преобразует полученные JSON в типы для View. Это то для чего и предназначена VM.
У Вас вся путаница из-за того что большая часть функций Модели возложена на VM. И в результате VM не делает того собственно для чего она предназначена.

Цитата Сообщение от Pro100Tom Посмотреть сообщение
Есть ли возможность создать Background свойство клетки со свойством корабля, если клетка уже связана с моделью Cell?
View не может быть связанной с Моделью!
VM, если не нужно преобразование, может напрямую передавать данные Модели прямо в её типах. Но такое возможно только в локальных приложениях. В общем же случае, перед передачей данных, VM их конвертирует в удобную для View форму.

Цитата Сообщение от Pro100Tom Посмотреть сообщение
Если нельзя, то норм ли имплементация где я в своей ViewModel создаю свойство, которое будет "следить" за свойством корабля IsSunk, и это свойство (класса ViewModel) будет забиндино
Да, это нормально.

Цитата Сообщение от Pro100Tom Посмотреть сообщение
Если ответ нет, то стоит ли забить на биндинги и просто удалить гланды через задницу?
Надо использовать те инструменты которые есть и тем образом для которого они предназначены.
Эти инструменты появились не на пустом месте - за ними десятки лет опыта миллионов программистов.
Если они для чего-то не подходят, то это, в первую очередь, вопрос к себе А на верном ли я пути?.
Конечно, как и любое творение рук человеческих, они не совершены.
Но прежде чем пытаться их изменять или использовать их не по назначению, надо научиться их использовать тем образом для которого они предназначены. И уже потом делать выводы.
1
29.05.2019, 18:16
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
29.05.2019, 18:16
Помогаю со студенческими работами здесь

свойства get;set;
Доброе время суток, решил на досуге почитать тут про лямбда выражения и с ужасом для себя открыл,...

Свойства set get
Написал код с использованием свойств, но они не используються( Тоесть они вроде есть, но смысла от...

Свойства get set
Доброй ночи. public class Date { private int month = 7; public int Month ...

Биндинг свойства контрола к одной из переменных свойства класса
Добрый день. У меня есть вопрос по биндингу. Ситуация следующая: У меня есть структура, ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
34
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru