вторник, 4 марта 2014 г.

[Из песочницы] Гибкое управление свойствами доступности элементов управления в обычных формах 1С: Предприятия 8.х

Наверное, одной из самых непростых и скучных задач при проектировании обычной формы в «1С: Предприятии» является управление доступностью элементов в зависимости от того или иного набора данных. Мне встречалось очень много решений: от процедуры вроде УстановитьВидимостьДоступность() с включением в нее всех правил для элементов управления, до совершенно хаотично разбросанных по всему коду обращений к указанным свойствам.

Признаюсь честно, я тоже перепробовал различные способы, но в один прекрасный момент дошел до очень удобного и логичного (как мне кажется), который и будет описан в этом посте.



Все началось с того, что поиск решения для этой задачи натолкнул меня на статью из «Методик разработки» под названием «Организация управления доступом в форме». Ключевым моментом в статье является то, что управление доступом сосредотачивается в одной лишь процедуре УстановитьДоступ(). И если необходимо изменить состояния элементов управления, вызывается только эта процедура. Сама процедура не занимается определением доступа, а работает с данными из списков, которые формируются следующими функциями:



ПолучитьСписокУправлениеВидимостью();
ПолучитьСписокУправлениеДоступностью();
ПолучитьСписокУправлениеТолькоПросмотр();
ПолучитьСписокДоступаКУправлениюВидимостью();




То есть сами условия доступности устанавливаются в этих функциях, а уже процедура УстановитьДоступ() присваивает соответствующим свойствам элементов управления эти заранее установленные значения.

Я разделил код на три составляющих. Первая — это методы, которые как раз выполняют изменения значений свойств доступности элементов формы. Вынес их в общий модуль. Назовем его условно УправлениеДоступом. Ниже расположен код, который размещается в нем. Я постарался максимально прокомментировать малопонятные участки кода.


Исходный код общего модуля УправлениеДоступом


////////////////////////////////////////////////////////////////////////////////
// ПРОЦЕДУРЫ УПРАВЛЕНИЯ ДОСТУПОМ К ЭЛЕМЕНТАМ ФОРМЫ

Функция ПолучитьСвойствоЭлементаФормы(Знач ЭлементУправления, Знач ИмяСвойства)

Результат = Неопределено;

Попытка
Результат = ЭлементУправления[ИмяСвойства];
Исключение

КонецПопытки;

Возврат Результат;

КонецФункции

Функция ПолучитьЭлементУправленияПоИмени(Форма, Знач ИмяЭлемента)

// Переменная хранит результат работы функции
ЭлементУправления = Неопределено;

ПозицияТочки = Найти(ИмяЭлемента, ".");

// Если имя элемента состоит из пути, например "Товары.Колонки.Номенклатура",
// разбиваем на составляющие и проходим путь до конечного элемента.
Если ПозицияТочки > 0 Тогда
// Получаем имя основного элемента управления
ЧастьИмени = Лев(ИмяЭлемента, ПозицияТочки - 1);

// Исключаем полученную часть из основного имени
ИмяЭлемента = Сред(ИмяЭлемента, ПозицияТочки + 1);

Элемент = ПолучитьСвойствоЭлементаФормы(Форма.ЭлементыФормы, ЧастьИмени);

Если Элемент <> Неопределено Тогда
ПозицияТочки = Найти(ИмяЭлемента, ".");

Пока ПозицияТочки > 0 Цикл
ЧастьИмени = Лев(ИмяЭлемента, ПозицияТочки - 1);
ИмяЭлемента = Сред(ИмяЭлемента, ПозицияТочки + 1);

Элемент = ПолучитьСвойствоЭлементаФормы(Элемент, ЧастьИмени);
Если Элемент = Неопределено Тогда
Возврат Неопределено;
КонецЕсли;

ПозицияТочки = Найти(ИмяЭлемента, ".");
КонецЦикла;

Элемент = ПолучитьСвойствоЭлементаФормы(Элемент, ИмяЭлемента);
ЭлементУправления = Элемент;
КонецЕсли;

Иначе
ЭлементУправления = Форма.ЭлементыФормы[ИмяЭлемента];
КонецЕсли;

Возврат ЭлементУправления;

КонецФункции

Процедура УстановитьДоступ(Форма) Экспорт

СписокУправлениеВидимостью = Форма.ПолучитьСписокУправлениеВидимостью();
Для Каждого ЭлементСписка Из СписокУправлениеВидимостью Цикл
ЭлементУправления = ПолучитьЭлементУправленияПоИмени(Форма, ЭлементСписка.Представление);

Если ТипЗнч(ЭлементУправления) = Тип("КолонкаТабличногоПоля") Тогда
Если ЭлементУправления.ИзменятьВидимость Тогда
ЭлементУправления.Видимость = ЭлементСписка.Значение;
Иначе
ЭлементУправления.ИзменятьВидимость = Истина;
ЭлементУправления.Видимость = ЭлементСписка.Значение;
ЭлементУправления.ИзменятьВидимость = Ложь;
КонецЕсли;
Иначе
ЭлементУправления.Видимость = ЭлементСписка.Значение;
КонецЕсли;
КонецЦикла;

СписокУправлениеДоступностью = Форма.ПолучитьСписокУправлениеДоступностью();
Для Каждого ЭлементСписка Из СписокУправлениеДоступностью Цикл
ЭлементУправления = ПолучитьЭлементУправленияПоИмени(Форма, ЭлементСписка.Представление);
ЭлементУправления.Доступность = ЭлементСписка.Значение;
КонецЦикла;

СписокУправлениеТолькоПросмотр = Форма.ПолучитьСписокУправлениеТолькоПросмотр();
Для Каждого ЭлементСписка Из СписокУправлениеТолькоПросмотр Цикл
ЭлементУправления = ПолучитьЭлементУправленияПоИмени(Форма, ЭлементСписка.Представление);
ЭлементУправления.ТолькоПросмотр = ЭлементСписка.Значение;
КонецЦикла;

СписокУправлениеРедактированиемТекста = Форма.ПолучитьСписокУправлениеРедактированиемТекста();
Для Каждого ЭлементСписка Из СписокУправлениеРедактированиемТекста Цикл
ЭлементУправления = ПолучитьЭлементУправленияПоИмени(Форма, ЭлементСписка.Представление);
ЭлементУправления.РедактированиеТекста = ЭлементСписка.Значение;
КонецЦикла;

КонецПроцедуры







Например, у нас есть табличное поле Товары, в котором присутствует колонка СкидкаПоДисконтнойКарте. Колонка видна только тогда, когда дисконтная карта проставлена в документ, т.е. реквизит ДисконтнаяКарта является заполненным. Соответственно, условие списока управления видимостью для колонки СкидкаПоДисконтнойКарте будет следующим:

Вторая часть когда — это функции, которые отвечают за формирование списков доступности. Они располагаются непосредственно в форме и являются экспортируемыми. Я немного отошел от стандарта 1С и заменил метод ПолучитьСписокДоступаКУправлениюВидимостью() на ПолучитьСписокУправлениеРедактированиемТекста(). Просто мне кажется, что так удобнее и логичнее. Ниже приведен шаблон кода с этими функциями:


Исходный код функций формирования списков управления доступом


////////////////////////////////////////////////////////////////////////////////
// ЭКСПОРТНЫЕ ПРОЦЕДУРЫ И ФУНКЦИИ

Функция ПолучитьСписокУправлениеВидимостью() Экспорт

СписокУправлениеВидимостью = Новый СписокЗначений;

Возврат СписокУправлениеВидимостью;

КонецФункции

Функция ПолучитьСписокУправлениеДоступностью() Экспорт

СписокУправлениеДоступностью = Новый СписокЗначений;

Возврат СписокУправлениеДоступностью;

КонецФункции

Функция ПолучитьСписокУправлениеРедактированиемТекста() Экспорт

СписокУправлениеРедактированиемТекста = Новый СписокЗначений;

Возврат СписокУправлениеРедактированиемТекста;

КонецФункции

Функция ПолучитьСписокУправлениеТолькоПросмотр() Экспорт

СписокУправлениеТолькоПросмотр = Новый СписокЗначений;

Возврат СписокУправлениеТолькоПросмотр;

КонецФункции







И, наконец, третья часть — это процедура УстановитьДоступ(), которая тоже расположена в модуле формы. Именно эту процедуру мы вызываем в любом месте кода нашей формы, чтобы переопределить доступность элементов формы.

////////////////////////////////////////////////////////////////////////////////
// ПРОЦЕДУРЫ И ФУНКЦИИ ОБЩЕГО НАЗНАЧЕНИЯ

Процедура УстановитьДоступ()

УправлениеДоступом.УстановитьДоступ(ЭтаФорма);

КонецПроцедуры




Чтобы было все нагляднее и понятнее, давайте рассмотрим следующий пример. Допустим, что у нас есть форма. На ней расположен флажок НаличнаяПродажа (булево), флажок ПробиватьФискальныйЧек (булево), поле ввода ДисконтнаяКарта (ссылка на справочник ДисконтныеКарты), поле ввода Комментарий (строка) и табличное поле Товары. Все связаны с одноименными реквизитами. У табличного поля есть колонка с именем СкидкаПоДисконтнойКарте (число). Кроме этого, есть командная панель ОсновныеДействияФормы, на которой размещена кнопка ПробитьЧек. Определим некоторые условия:

  1. Если установлен флажок НаличнаяПродажа, флажок ПробиватьФискальныйЧек видим и поле ДисконтнаяКарта доступно для ввода.

  2. Если стоит флажок ПробиватьФискальныйЧек, кнопка ПробитьЧек доступна.

  3. Если поле ДисконтнаяКарта заполнено, то видна колонка СкидкаПоДисконтнойКарте табличной части Товары и поле ввода Комментарий доступно для редактирования.




Тогда для нашего примера функции определения списков примут следующий вид:
Исходный код функций для примера


Функция ПолучитьСписокУправлениеВидимостью() Экспорт

СписокУправлениеВидимостью = Новый СписокЗначений;

ЗначениеВидимость = НаличнаяПродажа;
СписокУправлениеВидимостью.Добавить(ЗначениеВидимость, "ПробиватьФискальныйЧек");

ЗначениеВидимость = НЕ ДисконтнаяКарта.Пустая();
СписокУправлениеВидимостью.Добавить(ЗначениеВидимость, "Товары.Колонки.СкидкаПоДисконтнойКарте");

Возврат СписокУправлениеВидимостью;

КонецФункции

Функция ПолучитьСписокУправлениеДоступностью() Экспорт

СписокУправлениеДоступностью = Новый СписокЗначений;

ЗначениеДоступность = ПробиватьФискальныйЧек;
СписокУправлениеДоступностью.Добавить(ЗначениеДоступность, "ОсновныеДействияФормы.Кнопки.ПробитьЧек");

Возврат СписокУправлениеДоступностью;

КонецФункции

Функция ПолучитьСписокУправлениеРедактированиемТекста() Экспорт

СписокУправлениеРедактированиемТекста = Новый СписокЗначений;

ЗначениеРедактированиеТекста = НаличнаяПродажа И НЕ ДисконтнаяКарта.Пустая();
СписокУправлениеРедактированиемТекста.Добавить(ЗначениеРедактированиеТекста, "Комментарий");

Возврат СписокУправлениеРедактированиемТекста;

КонецФункции

Функция ПолучитьСписокУправлениеТолькоПросмотр() Экспорт

СписокУправлениеТолькоПросмотр = Новый СписокЗначений;

ЗначениеТолькоПросмотр = НаличнаяПродажа;
СписокУправлениеТолькоПросмотр.Добавить(ЗначениеТолькоПросмотр, "ДисконтнаяКарта");

Возврат СписокУправлениеТолькоПросмотр;

КонецФункции







Теперь достаточно вызвать процедуру формы УстановитьДоступ(), и мы получим то состояние элементов, которые задали.

Хочется выделить следующий момент. В списки можно можно добавлять пути к элементам формы. Например, для вышеприведенного примера с таблицей Товары имя элемента определяем как «Товары.Колонки.СкидкаПоДисконтнойКарте». Или путь к кнопке ПробитьЧек. Можно использовать множественные вложения, вроде «ИмяКоманднойПанели.Кнопки.ИмяПодменю.Кнопки.ИмяКнопки».


Предлагаемый вариант не конечный. Можно внести множество мелких дополнений, вроде указаний, какие списки обрабатывать, а какие нет. Но это уже зависит от точечных потребностей разработчика.


Спасибо за внимание.


This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


Комментариев нет:

Отправить комментарий