Резюме для программиста
Навеяло комментом из соседней темы
дисциплина. организоваать работу так, чтобы прерываться на бумаги, окно, просто откинуться на спинку стула, закрыть глаза и подумать над тем, чем занят. от пяленья в монитор гениальные решения редким идиотам приходят (их гениальность соответствует). настоящие приходят часто просто ночью, во сне. за питьем кофе, беседой с коллегами, ...
На дверях комнаты было написано что-то не совсем понятное: "Однодневная творческая путевка.
"Полнообъемные творческие отпуска от двух недель (рассказ-новелла) до одного года (роман, трилогия). Ялта, Суук-Су, Боровое, Цихидзири, Махинджаури, Ленинград (Зимний дворец)".
А ведь после творчества нужно ещё и отдохнуть! На это обычный отпуск должен выделяться. Ну а потом - снова за работу - в Ялту, к пальмам, к "мулаткам"! И всё это перемежая порционными судачками а натюрель, стерлядью кусками, переложенной раковыми шейками и свежей икрой, яйцами кокотт с шампиньоновым пюре в чашечках, филейчиками из дроздов с трюфелями, перепелами по-генуэзски и тарелочкой супа прентаньер. На веранде, в тени вьющегося винограда, под звуки джаза и с вежливой услугой. А как же иначе? По-другому вдохновение не приходит! Вобщем, работаем не покладая рук.
Думал, это только у МС беготня по фреймворкам и парад трупов. А нет - Гугл тоже не отстаёт. Выпустили в 2011, последний релиз в 2015. Всё, уже deprecated.
Вообще, этот WebAssembly какая-то хрень. Все с ней носятся уже несколько лет как с серебрянной пулей, но ни одного зрелого и надёжного фреймворка нет. В вебе продолжается разброд и шатание всяких технологий и фреймворков, и год от года только множится каша и пополняется кладбище разных "прорывных" проектов. Начнёшь проект на одном фреймворке, а через пару лет, как заканчивать будешь, он уже deprecated и ФААНГи орут о новом супер-пупер фреймворке.
А нет - Гугл тоже не отстаёт. Выпустили в 2011, последний релиз в 2015. Всё, уже deprecate
У них вроде запускается WebAssembly.
Кто-нибудь на WPF с такой байдой встречался?
В полях для ввода вводишь числа, и если валидация стоит на число с плавающей запятой и на изменение свойства (т.е. считай на ввод каждого символа), то эту самую запятую ввести и нельзя простым способом:
mvvm - WPF: Textbox and Binding to Double not able to type . on it - Stack Overflow
Это в новых версиях фреймворка после 4.0, а в старых - можно. Потому что МС захотела поменять это свойство.
Вот здесь описание проблемы Numeric text box data binding – www.mobilemotion.eu
Пипец, блин. Теперь любое старое приложение не работает нормально при обновлении версии. И хрен ты найдёшь ошибку. А клиенты со всех сторон наседуют - чё за фигня, не могу числа вводить?! И ты такой ищешь, ищешь, в чём же проблема - вроде, все валидации нормально работают, модели нормально написаны. А оно не даёт ввести точку или запятую с клавиатуры! И теперь КАЖДОЕ приложение должно быть написано с такой строкой как можно раньше при старте приложения (т.е. в классе App)
System.Windows.FrameworkCompatibilityPreferences.KeepTextBoxDisplaySynchronizedWithTextProperty =
false
;
Либо нужно прикручивать костыли (как в ответах на Stackoverflow) там, где раньше всё работало из коробки.
Просто попробуйте как в этой статье создать новый WPF проект и добавить текст бокс с привязкой к модели по свойству с плавающей запятой. Там главное - поставить обновление источника в байндинге не дефолтное, а по изменению свойства. С дефолтным баг не воспроизводится
<TextBox Text="{Binding Path=MyDouble, UpdateSourceTrigger=PropertyChanged}" />
Класс главного окна - тут просто контекст данных устанавливаем
public MainWindow() { InitializeComponent(); DataContext = new ViewModel(); }
Вот разметка окна - просто текст бокс кидаем и ставим байндинг
<Window x:Class="WpfApp1.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WpfApp1" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800" d:DataContext="{d:DesignInstance Type=local:ViewModel}"> <Grid> <TextBox Text="{Binding Path=MyDouble, UpdateSourceTrigger=PropertyChanged}" /> </Grid> </Window>
Ну и вью модель простая для привязки
public class ViewModel : INotifyPropertyChanged { #region INotifyPropertyChanged Members [field: NonSerialized] public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = "") { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } #endregion INotifyPropertyChanged Members double _myDouble; public double MyDouble { get => _myDouble; set { _myDouble = value; OnPropertyChanged(); } } }
В версиях 4.0 и младше баг не воспроизводится. В старших - воспроизводится. Причём что в 4.х, что в 5.0.
Нафига МС это сделала - непонятно. Может, там какие-то свои баги исправили. Но об этом никому не сообщили, и теперь куча народа с этой хернёй мается и должна откуда-то узнать, что теперь надо постоянно этот костыль вставлять куда-нибудь поближе к старту приложения (это свойство нельзя поменять потом).
Плавающая запятая вставляется из буфера обмена, но с клавы ввести нельзя. Никакую - ни точку, ни запятую (в зависимости от выбранной локали). В статье описывается, почему.
Ещё заметил такую штуку - можно ввести плавающую запятую первым символом, а потом цифры. Т.е. ввести дробное значение меньше 1. Но если вводить после любых цифт - т.е. дробное значение больше 1 - то не вводится.
Лечится либо добавлением этой строки как можно раньше при старте приложения
System.Windows.FrameworkCompatibilityPreferences.KeepTextBoxDisplaySynchronizedWithTextProperty =
false
;
либо костылями: задержками привязок, добавлением своих конвертеров во все байндинги даже там, где раньше всё работало без конвертеров по дефолту, ну и прочими штуками, как на Stackoverflow насоветовали.
Я такую штуку вписываю
// The inability to enter sometimes the floating point in text boxes comes from the Microsoft's changes in.NET Framework after version 4.0. // The solution is to change the KeepTextBoxDisplaySynchronizedWithTextProperty property to false as early as possible in the application - better in App class constructor. // https://www.mobilemotion.eu/?p=1855 // https://docs.microsoft.com/en-us/dotnet/api/system.windows.frameworkcompatibilitypreferences.keeptextbox //displaysynchronizedwithtextproperty?redirectedfrom=MSDN&view=windowsdesktop-6.0&viewFallbackFrom=net-5.0#remarks System.Windows.FrameworkCompatibilityPreferences.KeepTextBoxDisplaySynchronizedWithTextProperty = false;
Не знаю, что вы там делаете.
Вот пример для EN. Буквы и прочие символы ввести нельзя.
Бинарник не удалял. .NET 6.0
<TextBox Text="{Binding DoubleValue,StringFormat=N2}" PreviewTextInput="NumberValidator" />
Это вы уже свою логику, форматирование и валидаторов добавили. Я же не говорил, что это нерешаемая проблема. Можно обойти как угодно - кастомным конвертером, например. Проблема в том, что раньше работало по-умолчанию, а теперь без обмазки дополнительным кодом или разметкой вдруг перестало работать. И все старые проекты, написанные на 4.0- версиях фреймворка и где нет всяких обмазок, вдруг стали багованные.
Вот обошли заданием форматирования как у вас https://stackoverflow.com/a/31131932/5015385.
Можно своим конвертером.
Там по ссылке ещё монстрячат всякие простыни кода.
Но всё это надо на каждую проперть с плавающей точкой и привязкой к текстбоксу применять.
А можно одно свойство глобально заменить, как я показал.
Если вы с самого начала использования WPF всегда обмазывались тоннами кастомным фреймворков, своих собственных валидаторов, форматтеров и конвертеров, никогда не используя "чистые" вещи, то у вас это могло ни разу и не всплыть.
Я, например, этот ваш код с сеттером, в котором вызывается метод установки свойств, не понимаю. Я когда-то похожее самописное делал, а потом понял, что если долго это не видеть, а потом вернуться, то непонятно, что происходит - приходится снова лезть в вызовы, где там на самом деле происходит присвоение и когда проходит оповещение об изменении свойства. А чел, который после обычной статьи по MVVM придёт, вообще эту кашу не поймёт. У вас обычный сеттер превратился в кучу вызовов из намонстряченных сверху обёрток и "улучшателей". А если я хочу добавить ещё логики в сеттер, мне куда её поместить? До вызова вашего метода, после, или прямо в него?
В некоторых фирмах заставляют проекты на каких-то технологиях начинать всегда с неких корпоративных шаблонов, а не с нуля. Типа, того же WPF - есть шаблон, где уже настроен главный класс приложения (App), присоединены нужные библиотеки и корпоративные фреймворки, настроены нужные инжекторы, проинжектированы нужные сервисы, логгеры, настроены стили, пофикшены всякие баги установками нужных свойств (типа как выше описано), добавлены переменные с нужными путями для проекта (типа логов ошибок, файлов сохранений, настроек и т.п.), чтобы чел не занимался самодеятельностью, куда чего писать, и прочее. Т.е. ты каждый раз не с нуля проект начинаешь, а уже с шаблона, накачанного кодом по самое небалуйся. Главный альфа-кодер на фирме создал. ))
Можно обойти как угодно
А никто и не собирался ничего обходить просто сделал так как посчитал более удобным. Да и так тоже работает, хотя никогда бы и в голову не пришло пользовать
<TextBox Text="{Binding DoubleValue}" Width="150" HorizontalAlignment="Left" Margin="5"></TextBox>
никогда не используя "чистые" вещи
Всё нужно пользовать "правильно".
метод установки свойств, не понимаю
Ну так это уже ваши проблемы
Гораздо удобнее чем везде писать If
А если я хочу добавить ещё логики в сеттер
вообще то сеттер не предназначен для добавления логики. Но если очень хочется, то SetProperty возвращает bool
А никто и не собирался ничего обходить просто сделал так как посчитал более удобным. Да и так тоже работает, хотя никогда бы и в голову не пришло пользовать
Как не пришло, когда дефолтный триггер на обновление свойства для тектовых полей - потеря фокуса? А чтобы сделать валидацию на каждый введённый символ (частая задача - проверка правильности ввода "на лету"), нужно явно указать UpdateSourceTrigger. Вот после этого баг и возникает. Я проверял на версиях 3.5, 4.0, 4.1, 4.5, 5.0. На 6.0 не знаю.
Там вся соль именно в установке UpdateSourceTrigger на изменение свойства - т.е. ввод любого символа. Если оставить на потерю фокуса, как по дефолту, то вводить можно что угодно - триггер не срабатывает, и через привязку ничего не уходит. А именно из-за этого срабатывания удаляется первый введённый символ плавающей запятой. При этом можно ввести уже готовое число с плавающей запятой из буфера обмена. Я статью приводил - там это описано.
Ну так это уже ваши проблемы
Гораздо удобнее чем везде писать If
Какой if, вы о чём? Если о проверке, равно ли новое значение старому, то я в этом смысла не вижу. В большинстве случаев на это всё равно, и просто присваиваешь новое старому, даже если они равны. Если где-то логика приложения к этому критична, и надо случай одинаковых старого и нового значения отдельно обработать - просто делаешь отдельно для этого места проверку. В остальных случаях это лишние движения.
Я потому и отказался от универсальных сеттеров, потому что в разных местах надо логику немного поменять. Поэтому от универсальности сеттера не остаётся следа. Вы же эту свою строку SetProperty(value...) чего-то там пихаете в каждый сеттер копипастом? А в чём смысл? Просто меньше копипастить, чем раньше с if'ами? Если так лень копипастить и писать одинаковый код, то можно эту строку с SetProperty или блок с if'ом в сниппет запихать.
вообще то сеттер не предназначен для добавления логики
А то что?
Местный альфакодер запретил?