Вопрос
Если в TextBox вводится некорректная дата, то появляется сообщение "Invalid Date". Как можно проконтролировать корректность ввода даты до появления этого сообщения и заменить данное сообщение своим?
Ответ
Для начала следует задуматься о необходимости такой замены. Дело в том, что если Вы поставляете вместе с готовым файлом EXE русскоязычную Run-Time библиотеку с именем vfpXrrus.dll (X - цифра, соответствующая номеру версии Visual FoxPro), то вместо английского сообщения "Invalid Date" возникнет сообщение по-русски "Неверная дата".
Тем не менее, если Вы все-таки хотите произвести подмену вручную, то для этого есть способ.
Начиная с версии Visual FoxPro 5, для объекта TextBox добавлено свойство StrictDataEntry.
По умолчанию, это свойство имеет значение: 1 - Strict. Установите его в значение: 0 - Loose.
В этом случае, если введено некорректное значение даты, то никакого сообщения об ошибке вообще не возникает. Просто значение свойства TextBox.Value становиться пустым.
Это можно определить в событии TextBox.Valid() и выдать собственное сообщение об ошибке
* Событие TextBox.Valid
IF EMPTY(This.Value) = .T.
MessageBox("Дата введена некорректно!")
ENDIF
Однако при таком подходе возникают две проблемы:
1) Событие TextBox.Valid() наступает при выходе из объекта вне зависимости от того, изменяли Вы содержимое данного объекта или нет.
Это значит, что если значение поля изначально было пустым и пользователь в нем ничего не менял, а просто "прошел" через этот объект, например, при помощи клавиши Tab, то возникнет сообщение об ошибке. Чего быть не должно.
2) Если изначально дата уже была введена, а в процессе изменения пользователь ошибся, то желательно установить не пустое значение даты, а вернуть ее в исходное состояние. Т.е. установить то значение, которое было до редактирования.
Чтобы решить эти проблемы необходимо небольшое пояснение.
Если пользователь что-то изменяет в объекте, то на каждую модификацию срабатывает событие TextBox.InteractiveChage(). Но в данном случае недостаточно просто определить факт модификации. Необходимо определить тот факт, что пользователь пытался ввести не пустое значение.
То, что пользователь пытался ввести сохраняется в свойстве TextBox.Text. Точнее, в этом свойстве хранится то, что пользователь видит на экране, а не то, что сохраняется в свойстве TextBox.Value. Хотя значение этих свойств могут и совпадать. Но в общем случае это не так. Они отличаются, например, из-за используемых масок ввода.
К сожалению, нельзя просто сравнить в событии TextBox.Valid() значение свойств TextBox.Value и TextBox.Text. Дело в том, что если объект TextBox имеет не пустое значение свойства TextBox.ControlSource (например, TextBox "привязан" к полю таблицы), то к моменту выполнения события TextBox.Valid() в случае ошибки ввода свойство TextBox.Text также окажется пустым. Отдельное спасибо Андрею Тарасову (XAndy), обратившему на это внимание.
Следовательно, необходимо в событии TextBox.InteractiveChange() организовать сохранение текущего значения свойства TextBox.Text. И если в событии TextBox.Valid() окажется, что значение TextBox.Value пустое, а сохраненное значение TextBox.Text не пустое, то это и будет означать ошибку ввода.
Аналогичным образом следует поступить и для восстановления значения до редактирования. Надо просто сохранить исходное значение. Процедуру сохранения выполнить при входе в объект. Либо в событии TextBox.When(), либо в событии TextBox.GotFocus().
У любого объекта FoxPro есть два дополнительных свойства: Tag и Comment. Это свойства-комментарии. Они никак не влияют на работу объекта и предназначены для хранения справочной информации. Следует только иметь в виду, что они принимают значения только и исключительно символьного типа. Вот эти-то два свойства и используем для хранения нужных значений.
В результате, после всех пояснений, получаем такой код:
* Событие TextBox.When
This.Comment = DTOC(This.Value)
* Событие TextBox.InteractiveChange
* Используется TransForm(), а не DTOC(),
* поскольку значение This.Text может не преобразовываться в дату
This.Tag = TransForm(This.Text)
* Событие TextBox.Valid
* Значение, которое попытался ввести пользователь
LOCAL lcUserText
lcUserText = This.Tag
* Очищаем сохраненное значение
This.Tag = ""
* Сравниваю то, что реально введено с тем, что пытались ввести
* Предполагаю, что реально введено то, что должно вернуть Ctod(m.lcUserText)
If Empty(m.lcUserText)=.F. AND m.lcUserText <> Dtoc(Ctod(m.lcUserText))
This.Value = Ctod(This.Comment)
MessageBox("Неверный ввод даты")
* Если хотите запретить выход из объекта,
* то снимите комментарий со следующей команды
* Return 0
EndIf
Вам решать, стоит ли полученный результат затраченных усилий.
Замечание
Если объект TextBox, не связан ни с каким источником данных. Т.е. и TextBox.ControlSource, и TextBox.Value при открытии формы не указаны. То для того, чтобы символы разделители в дате не съезжали при вводе, необходимо указать нужный формат