Добрый день, друзья!
Недавно стал участником перехода с платформы 8.2 на 8.3. База старая и сто раз переписанная. К сожалению, непосредственное участие принять не удалось, зато мне выпала честь исправлять появившиеся баги после перехода. Пару самых интересных по моему мнению опишу в этой статье.
Пояснения: переход осуществлялся с версии платформы 8.2.19.130 на 8.3.13.1690. И конфигурация написана на обычных формах (на самом деле там всё смешано, но большая часть на обычных), то есть все случаи будут затрагивать работу в обычном приложении. Ладно, поехали.
Случай 1.
Предисловие.
Мы все хорошо знаем, что при автоподборе текста стандартный алгоритм такой: ищутся первые 50 записей, найденных по реквизитам, указанным в параметре "Ввод по строке" объекта вот здесь:
При обусловненной необходимости этот список можно дополнить, но, естественно, добавляемое поле должно быть проиндексировано. Если есть всего одна найденная запись, то оставшаяся часть строки ввода добавляется; нет нужды всё описывать в подробностях. Если найденных записей не больше пятидесяти, то выпадает список выбора значения, а, если больше, то ничего не происходит.
Теперь посмотрим, как происходит автоподбор текста на разных платформах:
- 8.2. Всё как обычно.
- 8.3. После автоподбора курсор переносится в конец подобранной строки.
Для тех, кто смотрит в монитор или пишет быстрее того момента, когда срабатывает обработчик, это, может быть, и не проблема. У остальных же это вызвало, мягко говоря, недовольство. Что поделать, придется переписывать стандартную обработку...
Для начала, нужно получить из метаданных все поля ввода по строке и в соответствии с этим формировать запрос. Прилагаю листинг ниже.
Процедура ПолеВвода1АвтоПодборТекста(Элемент, Текст, ТекстАвтоПодбора, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
ТекстЗапросаПоле = "";
ТекстЗапросаУсловие = "";
КоличествоПолейВводаПоСтроке = Метаданные.Справочники.НомераГТД.ВводПоСтроке.Количество();
Для ТекСтрока = 1 По КоличествоПолейВводаПоСтроке Цикл
ПолеВводПоСтроке = Метаданные.Справочники.НомераГТД.ВводПоСтроке.Получить(ТекСтрока - 1);
ТекстЗапросаПоле = ТекстЗапросаПоле + "
| КОГДА НомераГТД." + ПолеВводПоСтроке.Имя + " ПОДОБНО &Текст
| ТОГДА НомераГТД." + ПолеВводПоСтроке.Имя;
ТекстЗапросаУсловие = ?(ТекСтрока = 1, "(", "") + ТекстЗапросаУсловие + "
| НомераГТД." + ПолеВводПоСтроке.Имя + " ПОДОБНО &Текст" + ?(ТекСтрока = КоличествоПолейВводаПоСтроке, ")", Символы.ПС + "ИЛИ ");
КонецЦикла;
Запрос = Новый Запрос;
Запрос.УстановитьПараметр("Текст", Текст + "%");
Запрос.Текст =
"ВЫБРАТЬ
| ВЫБОР"
+ ТекстЗапросаПоле + "
| КОНЕЦ КАК ТекстАвтоПодбора,
| НомераГТД.Представление,
| НомераГТД.Ссылка
|ИЗ
| Справочник.НомераГТД КАК НомераГТД
|ГДЕ " + ТекстЗапросаУсловие;
РезультатЗапроса = Запрос.Выполнить();
Если Не РезультатЗапроса.Пустой() Тогда
Выборка = РезультатЗапроса.Выбрать();
КоличествоЗаписей = Выборка.Количество();
Если Выборка.Количество() = 1 Тогда
Выборка.Следующий();
ТекстАвтоПодбора = Выборка.ТекстАвтоПодбора;
ИначеЕсли Выборка.Количество() <= 50 Тогда
СписокВыбора = Новый СписокЗначений;
Пока Выборка.Следующий() Цикл
СписокВыбора.Добавить(Выборка.Ссылка,
?(Выборка.ТекстАвтоПодбора = Выборка.Представление, СокрЛП(Выборка.ТекстАвтоПодбора), СокрЛП(Выборка.ТекстАвтоПодбора) + " (" + СокрЛП(Выборка.Представление) + ")"));
КонецЦикла;
ВыбранноеЗначение = ВыбратьИзСписка(СписокВыбора, Элемент);
Если ВыбранноеЗначение <> Неопределено Тогда
Элемент.Значение = ВыбранноеЗначение.Значение;
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Можно было бы не париться и просто обратиться с поиском по коду. С другой стороны, мы хотим повторить полный функционал платформы и нам нельзя игнорировать настройки, указанные в метаданных. После формирования запроса проверяем количество записей результата: если запись одна, то просто приравниваем результат к параметру ТекстАвтоПодбора. Интересно, что, если вручную установить этот параметр, то баг пропадет. Если записей не больше пятидесяти, то формируем список значений и формируем выбор из списка. Для оптимизации запроса можно, конечно, вписать "ВЫБРАТЬ ПЕРВЫЕ 51", но я подумал, что это может выжечь кому-нибудь глаза, поэтому не стал:)
Вроде готово, смотрим результат:
- когда найденная запись только одна;
- когда записей несколько;
Также, когда записей несколько, но они найдены не по полю основного представления, то представление элемента нужно также внести в скобки в списке выбора. Для теста специально добавил в поля ввода ещё один реквизит. Процесс добавления:
-внес в индекс
- добавил в поля ввода по строке.
Результат автоподбора текста:
Вот так в итоге получилось.
Случай 2.
Предисловие.
В некоторых ситуациях при изменении поля ввода необходимо, чтобы курсор возвращался в это же поле. К примеру, это подходит для тех полей, куда вносится штрих-код: чтобы сработал обработчик ПриИзменении приходится после сканирования вставлять символ переноса каретки, после это поле очищается и курсор переносится туда же.
Итак, вот какой жук нашелся. Для наглядности создам обработку с двумя строчками кода при изменении поля ввода: первая строчка очищает значение элемента, вторая устанавливает свойство ТекущийЭлемент = Элемент. Смотрим:
- 8.2 всё ок;
- 8.3 вторая строчка кода не срабатывает...
Окей. Конечно, от этого никто не помрёт, но эмоций, поверьте, много, особенно у тех, кто пользуется сканером штрих-кода... Как это исправить? Что только ни пытался сделать. Пробовал в конце обработчика ставить строчку Элемент.ВыделенныйТекст = " ". В каком-то смысле это помогло, однако, в поле ввода красовался пробел, что совсем нам не нужно.
Нашелся выход из данной ситуации не сказать, что прямо идеальный, но другого выхода не нашлось. С выходом платформы 8.3 на форме появился новый обработчик ОбновлениеОтображения. Хотя в методичке по этому обработчику говорится, что так делать нельзя из-за возможности падения производительности системы, как я уже говорил, другого выхода не нашлось. Итак, пишу листинг:
Перем ЭтоИзменениеНужногоПоля;
Процедура ПолеВводаПостояннымКурсоромПриИзменении(Элемент)
Элемент.Значение = "";
КонецПроцедуры
Процедура ОбновлениеОтображения()
Если ЭтоИзменениеНужногоПоля Тогда
ТекущийЭлемент = ЭлементыФормы.ПолеВводаПостояннымКурсором;
КонецЕсли;
КонецПроцедуры
Процедура ПолеВводаПостояннымКурсоромОкончаниеВводаТекста(Элемент, Текст, Значение, СтандартнаяОбработка)
Если ЗначениеЗаполнено(Элемент.Значение) Тогда
ЭтоИзменениеНужногоПоля = Истина;
КонецЕсли;
КонецПроцедуры
ЭтоИзменениеНужногоПоля = Ложь;
Итак, создаю глобальную переменную формы ЭтоИзменениеНужногоПоля. Она нужна для того, чтобы возврат в нужный элемент формы происходил только после нужного мне события. При окончании ввода текста в нужном поле ввода при заполненном значении устанавливаю значение моей переменной в Истина. После всех обработчиков срабатывает обработчик ОбновлениеОтображения. Там я проверяю, что, если изменено нужное поле, то ставлю ТекущийЭлемент в нужный элемент формы. Вуаля. Результат:
- норм.
Вроде бы косяки и мелкие, но пришлось достаточно попотеть, чтобы их устранить. После всего я подумал, что на 8.3 лучше работать на управляемых формах... Может, я здесь, конечно, и не прав. В любом случае хочу сказать, что в таких ситуациях, когда перестают работать привычные для тебя методы работы и приходится в быстром порядке придумывать новые, получаешь наибольший опыт. Такой выход из зоны комфорта помогает взглянуть на привычные вещи с другой стороны и ещё это весело. Но это не точно:)