Здравствуйте, ambel-vlad, Вы писали:
MK>>Амбил-Влад, тебе помочь расставить плюсо-минусы AV>Нда, не знал, что у тебя еще и с глазами проблемы.
Мне думается, коллега, что это наступление весны вызывает сезонное обострение у тех, кто любит покидаться какашками на форумах.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Здравствуйте, Cyberax, Вы писали:
C>Чем? У меня НЕТ поля ViewModel.UserAge в модели данных.
В модели данных его и не должно быть, очевидно.
C>Грубо говоря, у меня есть DataModel.DateOfBirth, которую надо привязать к контролу с возрастом. Как ты это будешь делать?
А какие проблемы? Во ViewModel может быть как возраст, так дата рождения, в зависимости от того, что удобнее, и что лучше отражает представление (ViewModel — модель представления, а не представление модели).
Здравствуйте, Cyberax, Вы писали:
C>Здравствуйте, gandjustas, Вы писали:
G>>Так не надо валить в кучу валидность и databinding. В wpf эти задачи разделены, есть Binding для связывания, а есть IDataErrorInfo для доставки пользователю информации о валидноси введенных данных. G>>Вы нарушаете SRP от этого у вас проблемы. WPF тут не при чем. C>Я уж десять раз повторяю, что мне для отдельного контрола байндинг особого смысла не имеет. Нужно делать байндинг на уровне всей формы (или группы форм сразу), с учётом связей и зависимостей.
Нут так это и есть viewmodel.
C>>>Ещё есть шутки с граничными условиями. Например, у нас есть два режима вычисления при значении N ползунка N>50 и N<50. Мы подводим к 49 и из-за округления он устанавливается на 51, а обратное вычисление скидывает его на 50, которое округляется до 49, которое снова устанавливается в 51 и т.д. G>>А причем тут интерфейс? Вы и код не сможете написать что бы он так работал, у вас сразу же бесконечный цикл получится. C>Смогу. У меня есть детектор таких циклов (зря ты думаешь оно 180Кб занимает и использует rule engine?) — в этом случае прекращается вычисление всей зацикленной группы контролов и они помечаются как ошибочные.
Так пусть он этим в коде и занимается, причем тут UI и контролы?
G>>>>Ну так вам и флаг в руки, напишите код который парсит xml и создает нужные контролы. C>>>Так написали. Создать контролы и показать их — это фигня, мелочь. Проблема что с ними дальше делать. G>>При нормальном подходе больше ничего с контролами делать не надо, все остальные проблемы ложаться на viewmodel. В которой нету трахов с байндингом, валидацией и прочей мутью. C>Не, ну ладно. Сделали для каждого контрола поле во viewmodel, которое автоматически синхронизируется с контролом. Причём куча полей будет абсолютно искусственными, так как привязать поле к результату вычисления напрямую — сложно.
Ну так правильно, ваш vewmodel становится контейнером всей сложной логики, вам тогда вообще пофигу становится вся работа с UI.
Это же прекрасно.
C>И чего мы в итоге добились? Чем "myViemodel.name" отличается от 'getControl("controlName").getText()' для дальнейшего использования в вычислениях?
myViemodel.name типизировано гораздо сильнее, чем getControl("controlName").getText().
Кроме того myViemodel.name очень легко покрыть тестами, а getControl и все что через него делается — нереально.
Здравствуйте, Cyberax, Вы писали:
Q>>Тем, что во втором случае ты не можешь просто заменить одну морду на другую (тестовую/эмулирующую или просто альтернативную), придётся копипастить и править логику представления — ведь она у тебя прямо завязана на контролы. Ты даже не можешь без приключений переименовать контрол, потому что это придётся делать не с помощью синтаксического анализатора, а с помощью небезопасного лексического (тупой поиск строки в текстовых литералах). Не говоря уже о том, что ViewModel.UserAge куда выразительнее отражает идею, чем int.parse(getControl("userNameTextBox").getText()). C>Чем? У меня НЕТ поля ViewModel.UserAge в модели данных. Грубо говоря, у меня есть DataModel.DateOfBirth, которую надо привязать к контролу с возрастом. Как ты это будешь делать?
А кто сказал что такое поле должно быть в модели данных?
MVVM, как и MVP и MVC создаются чтобы абстрагировать UI от модели данных и логики работы с ними.
Здравствуйте, ambel-vlad, Вы писали:
AV>Да перестал уже различать людей
То, что я отвечаю на постинг CreatorCray не означает, что я в нем не могу обращаться к другим людям. Заметь, плюсик то ты поставил. Это именно то, что я имел ввиду
Здравствуйте, olegkr, Вы писали:
O>Здравствуйте, VladD2, Вы писали:
VD>>Если бы вы перевели его скажем на Немерле или F# (с умом), то он бы стал еще более лаконичным и читабельным (раз эдак в 5). O>Ну так переведи вышепроцитированный код на немерле или f#, а мы поаппладируем в восхищении!
Вот этот что ли:
class SomeClass<T>
{
public T Property1 { get; set; }
public T Property2 { get; set; }
}
var someClass = new SomeClass<string>
{
Property1 = "some string",
ListProperty = { "string1", "string2" }
};
?
Он слшком примитивен, чтобы на нем получить серьезный выигрышь. К тому же он не несет смысловой нагрузки. Так что тяжело понять задачу.
К тому же код откровенно ошибочен. Что за ListProperty? И где Property2?
Подозреваю, что имелось в виду что-то вроде:
class SomeClass<T>
{
public T Property1 { get; set; }
public List<T> ListProperty { get; set; }
}
var someClass = new SomeClass<string>
{
Property1 = "some string",
ListProperty = { "string1", "string2" }
};
Могу предложить два вариата. Первый чисто синтаксические улучшения:
[Record] // этот макрос создает конструктор который инициализирует все члены классаclass SomeClass[T]
{
public Property1 : T { get; private set; }
public ListProperty : list[T] { get; private set; }
}
def someClass = SomeClass("some string", ["string1", "string2"]);
Уже имеем выигрыш в 4 строки плюс SomeClass стал неизменяемой структурой данных, что упростит отладку и увеличит надежность кода.
Другой вариант вместо класса использовать вариантный тип. Такой вариант подходит когда нужно описать некие связанные сущности (аля иерархия классов):
[Record] // этот макрос создает конструктор который инициализирует все члены класса
variant SomeVariant[T]
{
| SomeVariantOption1 { data : T; listData : list[T]; }
| другие вхождения
}
def some = SomeVariant.SomeVariantOption1("some string", ["string1", "string2"]);
[/c#]
Далее варианты можно распознавать с помощью мощьного оператора match:
match (some)
{
| SomeVariantOption1(data, ["string1", "string2"]) => что-то делаем... в data значение поля "data".
| _ => обработка не распознанных вариантов...
}
Обрати внимание. Указывать параметры типов не нужно во все. А мощность оператора match настолько велика, что он позволяет распознавать сложные иерархии объектов.
В купе с другими фичами языка это позволят сокращать код от двх, до десятков раз.
И это только возможности языка. А если к ним прибавить возможности макросов, то можно достигнуть многократного приемущества. Так ты можешь просто создать совой ДСЛ и описать логику на нем. А макросы сгенерируют оптимальный код реализации.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
VD>Могу предложить два вариата. Первый чисто синтаксические улучшения: VD>
VD>[Record] // этот макрос создает конструктор который инициализирует все члены класса
VD>class SomeClass[T]
VD>{
VD> public Property1 : T { get; private set; }
VD> public ListProperty : list[T] { get; private set; }
VD>}
VD>def someClass = SomeClass("some string", ["string1", "string2"]);
VD>
VD>Уже имеем выигрыш в 4 строки плюс SomeClass стал неизменяемой структурой данных, что упростит отладку и увеличит надежность кода.
Так это не правильно. Во-первых, в оригинале нет никакого конструктора (кроме по-умолчанию). Во-вторых, а что произойдет, если свойств не 2, а 20 или 40? Ну и наконец нечитабельно ведь — надо смотреть на сигнатуру этого конструктора, которой у нас, собственно, ведь нету в design time.
VD>Другой вариант вместо класса использовать вариантный тип. Такой вариант подходит когда нужно описать некие связанные сущности (аля иерархия классов):
VD>[Record] // этот макрос создает конструктор который инициализирует все члены класса VD>variant SomeVariant[T] VD>{ VD> | SomeVariantOption1 { data : T; listData : list[T]; } VD> | другие вхождения VD>}
VD>def some = SomeVariant.SomeVariantOption1("some string", ["string1", "string2"]); VD>[/c#]
Интересно.. а что нам дает такая конструкция? Можно чуть подробнее?
VD>Далее варианты можно распознавать с помощью мощьного оператора match: VD>
VD>match (some)
VD>{
VD> | SomeVariantOption1(data, ["string1", "string2"]) => что-то делаем... в data значение поля "data".
VD> | _ => обработка не распознанных вариантов...
VD>}
VD>
VD>Обрати внимание. Указывать параметры типов не нужно во все. А мощность оператора match настолько велика, что он позволяет распознавать сложные иерархии объектов.
Да, это полезно.
VD>В купе с другими фичами языка это позволят сокращать код от двх, до десятков раз.
Здравствуйте, criosray, Вы писали:
VD>>Уже имеем выигрыш в 4 строки плюс SomeClass стал неизменяемой структурой данных, что упростит отладку и увеличит надежность кода.
Кстати, по поводу выигрыша по строками на таком простом примере выигрывает все-таки С#:
1 class SomeClass<T>
2 {
3 public T Property1 { get; set; }
4 public List<T> ListProperty { get; set; }
5 }
6 var someClass = new SomeClass<string> { Property1 = "some string", ListProperty = { "string1", "string2" }};
против
1 [Record] // этот макрос создает конструктор который инициализирует все члены класса
2 class SomeClass[T]
3 {
4 public Property1 : T { get; private set; }
5 public ListProperty : list[T] { get; private set; }
6 }