Создаем универсальный механизм отбора и сортировки для управляемых форм





Причиной этого труда стало: отсутствие привычной кнопки "Отбор по значению в текущей колонке", некоторые проблемы с динамическими списками, отсутствие истории отборов, авто восстановления настроек отборов при перезапуске формы (динамических списков), а так же стремление увеличить функциональность отборов и сортировок с учетом возможностей управляемых форм.

Осноные возможноси:

1. Отбор имеет полный функционал как и в 1С Предприятие 8.1;

2. Отсутсвует ошибка при использовании истории отборов (в 1С Предприятии 8.1 если установлен отбор и воспользоватся отбором из истории текущий отбор не отменяется);

3. Возможность использования отборов и сортировки для всех возможных реквизитов, которые присутствуют в таблице и тех которые добавлены через команду формы «Изменить форму» (Например, Номенклатура.Ссылка.Ссылка.ВидНоменклатуры.Код);

4. Сортировка по любому реквизиту в таблице;

5. История отборов размером в 20 элементов;

6. Все построенно на СКД с выводом в таблицу значений, что дает возможность использовать дополнительные поля которые есть в запросе;

7. Минимум серверных вызовов;

8. Для использования в своих разработках достаточно изменить запрос в наборе данных, структуру полей компоновщика (ПриСозданииНаСервере) и подкоректировать таблицу значений для вывода.




Код обработки, работоспособен в конфигурации УТ 11:

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
   
//1. Создаем схему компоновки данных
   
СхемаКомпоновкиДанных = Новый СхемаКомпоновкиДанных;
   
//1.1 определяем источник данных для схемы
   
ИсточникДанных = СхемаКомпоновкиДанных.ИсточникиДанных.Добавить();
   
ИсточникДанных.Имя                = «ИсточникДанных»;
   
ИсточникДанных.СтрокаСоединения   = «»;
   
ИсточникДанных.ТипИсточникаДанных = «Local»;
   
//1.2 определяем набор данных
   
НаборДанных = СхемаКомпоновкиДанных.НаборыДанных.Добавить(Тип(«НаборДанныхЗапросСхемыКомпоновкиДанных»));
   
НаборДанных.Имя            = «НаборДанных»;
   
НаборДанных.ИсточникДанных = «ИсточникДанных»;
   
НаборДанных.АвтоЗаполнениеДоступныхПолей = Истина;
   
НаборДанных.Запрос = «
        |ВЫБРАТЬ
        |   СпрНоменклатура.Ссылка КАК Номенклатура,
        |   СвободныеОстатки.ВНаличииОстаток КАК ВНаличии,
        |   СвободныеОстатки.ВРезервеОстаток КАК ВРезерве
        |
        |ИЗ
        |   Справочник.Номенклатура КАК СпрНоменклатура
        |
        |ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.СвободныеОстатки.Остатки КАК СвободныеОстатки
        |ПО СпрНоменклатура.Ссылка = СвободныеОстатки.Номенклатура
        |
        |ГДЕ
        |НЕ СпрНоменклатура.ЭтоГруппа
        |И  СпрНоменклатура.Родитель = &ГруппаНоменклатуры»
;

    //1.2.1 добавляем поля
   
ПолеНоменклатуры = НаборДанных.Поля.Добавить(Тип(«ПолеНабораДанныхСхемыКомпоновкиДанных»));
   
ПолеНоменклатуры.ПутьКДанным = «Номенклатура»;
   
ПолеНоменклатуры.Заголовок   = «Номенклатура»;
   
ПолеНоменклатуры.Поле        = «Номенклатура»;

    //1.3 определяем ресурсы
    //ПолеРесурса = СхемаКомпоновкиДанных.ПоляИтога.Добавить();
    //ПолеРесурса.Выражение = «»;
    //ПолеРесурса.ПутьКДанным = «»;

    //2. создаем настройки для схемы
    //НастройкиКомпоновкиДанных = СхемаКомпоновкиДанных.НастройкиПоУмолчанию;
    АдресСхемыКомпоновкиДанных = ПоместитьВоВременноеХранилище(СхемаКомпоновкиДанных, УникальныйИдентификатор);
   
КомпоновщикНастроек.Инициализировать(Новый ИсточникДоступныхНастроекКомпоновкиДанных(АдресСхемыКомпоновкиДанных));

    //2.1 определяем структуру
    //2.1.1 добавляем группировку «Номенклатура»
   
ГруппировкаНоменклатуры = КомпоновщикНастроек.Настройки.Структура.Добавить(Тип(«ГруппировкаКомпоновкиДанных»));
   
ГруппировкаНоменклатуры.Использование = Истина;

    //2.2 определим выбранные поля
   
ВыбранноеПоле = ГруппировкаНоменклатуры.Выбор.Элементы.Добавить(Тип(«ВыбранноеПолеКомпоновкиДанных»));
   
ВыбранноеПоле.Заголовок     = «Номенклатура»;
   
ВыбранноеПоле.Использование = Истина;
   
ВыбранноеПоле.Поле          = Новый ПолеКомпоновкиДанных(«Номенклатура»);

    ВыбранноеПоле = ГруппировкаНоменклатуры.Выбор.Элементы.Добавить(Тип(«ВыбранноеПолеКомпоновкиДанных»));
   
ВыбранноеПоле.Заголовок     = «ВНаличии»;
   
ВыбранноеПоле.Использование = Истина;
   
ВыбранноеПоле.Поле          = Новый ПолеКомпоновкиДанных(«ВНаличии»);

    ВыбранноеПоле = ГруппировкаНоменклатуры.Выбор.Элементы.Добавить(Тип(«ВыбранноеПолеКомпоновкиДанных»));
   
ВыбранноеПоле.Заголовок     = «ВРезерве»;
   
ВыбранноеПоле.Использование = Истина;
   
ВыбранноеПоле.Поле          = Новый ПолеКомпоновкиДанных(«ВРезерве»);

    ГруппировкаНоменклатуры.Порядок.Элементы.Добавить(Тип(«АвтоЭлементПорядкаКомпоновкиДанных»));
КонецПроцедуры

&НаКлиенте
Процедура ПриОткрытии(Отказ)
   
//Проводим инициализацию отборов из загруженных данных при последнем сохранении
   
ИнициализироватьОтборы();
   
//Обновляем пометки кнопок для визуального восприятия отборов
   
ОбновитьДанныеОтбора();
КонецПроцедуры

&НаСервере
Процедура ИнициализироватьОтборы()
   
//Список значений «ИсторияОтборов» хранит историю отборов, максимум 20 элементов
   
Для і=0 По ИсторияОтборов.Количество()-1 Цикл
       
//Получаем имя команды которая соответствует отбору
       
ИмяКоманды = ИсторияОтборов[і].Значение.ИмяКоманды;
       
//Получаем представление отбора, которое является аналогичным 1С 8.1
       
Представление = ПолучитьПредставлениеОтбора(ИсторияОтборов[і].Значение.МассивОтборов);
       
//Динамически добавляем команду формы и добавляем элемент формы, который привязываем к команде формы
       
ДобавитьКомандуКФорме(ИмяКоманды, Представление);
    КонецЦикла;
КонецПроцедуры

&НаКлиенте
Процедура ИерархияНоменклатурыПередНачаломИзменения(Элемент, Отказ)
   
//Запрет изменения элементов пользователю
   
Отказ = Истина;
КонецПроцедуры

&НаКлиенте
Процедура ИерархияНоменклатурыПередУдалением(Элемент, Отказ)
   
//Запрет удаления элементов пользователю
   
Отказ = Истина;
КонецПроцедуры

&НаКлиенте
Процедура ИерархияНоменклатурыПередНачаломДобавления(Элемент, Отказ, Копирование, Родитель, Группа)
   
//Запрет добавления элементов пользователю
   
Отказ = Истина;
КонецПроцедуры

&НаКлиенте
Процедура ИерархияНоменклатурыПриАктивизацииСтроки(Элемент)
   
//Так как это пример, решил упростить задачу — не обрабатывать пустую ссылку
   
Если Элемент.ТекущаяСтрока.Пустая() Тогда
       
ТаблицаНоменклатуры.Очистить();
    Иначе
       
СформироватьКлиент(Элемент.ТекущаяСтрока);
    КонецЕсли;
КонецПроцедуры

&НаКлиенте
Процедура СформироватьКлиент(ГруппаНоменклатуры, Отбор = Ложь, Сортировка = Ложь, Идентификатор = Неопределено, ИмяЭлемента = Неопределено)
    Перем
ПараметрыОтбора;
   
//Запомним данные, возможно нам понадобится востановить курсор пользователя
   
ТекущиеДанные = Элементы.ТаблицаНоменклатуры.ТекущиеДанные;
    Если НЕ
ТекущиеДанные = Неопределено Тогда
        
ПараметрыОтбора = Новый Структура(«Номенклатура», ТекущиеДанные.Номенклатура);
    КонецЕсли;

    СформироватьСервер(ГруппаНоменклатуры, Отбор, Сортировка, Идентификатор, ИмяЭлемента);
   
//Обновляем пометки кнопок для визуального восприятия отборов
   
ОбновитьДанныеОтбора();

    //Востанавливаем курсор на позицию, если она не пропала из выгрузки
   
Если НЕ ПараметрыОтбора = Неопределено Тогда
       
Массив = ТаблицаНоменклатуры.НайтиСтроки(ПараметрыОтбора);
        Если
Массив.Количество() Тогда Элементы.ТаблицаНоменклатуры.ТекущаяСтрока = Массив[0].ПолучитьИдентификатор(); КонецЕсли;
    КонецЕсли;
КонецПроцедуры

&НаСервере
Процедура СформироватьСервер(ГруппаНоменклатуры, Отбор = Ложь, Сортировка = Ложь, Идентификатор = Неопределено, ИмяЭлемента = Неопределено)
    Перем
Значение, ВремОбъект;
   
//Получаем СКД из временного хранилища
   
СхемаКомпоновкиДанных   = ПолучитьИзВременногоХранилища(АдресСхемыКомпоновкиДанных);
   
КомпоновщикНастроек.Настройки.ПараметрыДанных.УстановитьЗначениеПараметра(«ГруппаНоменклатуры», ГруппаНоменклатуры);
   
//У пользователя есть возможность изменять форму, нужно проверить имя реквизита — возможно реквизит был добавлен через «Изменить форму…»
   
Если Отбор ИЛИ НЕ Сортировка = Ложь Тогда
       
ТекущиеДанные = ТаблицаНоменклатуры.НайтиПоИдентификатору(Идентификатор);
       
//Проверяем есть ли реквизит
       
РеквизитИзТаб = ТекущиеДанные.Свойство(ИмяЭлемента, Значение);
        Если
РеквизитИзТаб Тогда
            Если
Отбор Тогда
               
ДобавитьОтборПоЗначению(КомпоновщикНастроек, ИмяЭлемента, Значение);
               
ОбновитьИсториюОтборов(КомпоновщикНастроек, ИсторияОтборов);
            Иначе
               
ДобавитьСортировку(КомпоновщикНастроек, ИмяЭлемента, Сортировка);
            КонецЕсли;
        Иначе
           
//Реквизита нет в таблице, разбиваем ИмяЭлемента на слова
           
МассивИмен = ПолучитьМассивИмен(ИмяЭлемента);
           
Колич_Имен = МассивИмен.Количество() — 1;

            //Данный цикл предназначен для поиска реквизита ссылочного типа, который является родителем реквизита по которому
            //выполняется отбор или сортировка
           
Для i = 0 По Колич_Имен Цикл
                Если
ТекущиеДанные.Свойство(МассивИмен[i], ВремОбъект) Тогда
                    Если
Найти(XMLТипЗнч(ВремОбъект).ИмяТипа, «Ref») = 0 Тогда
                       
//Добавлять дополнительные поля возможно только из реквизитов ссылочного типа
                       
ВызватьИсключение «Возникла неизвестная ошибка. Реквизит имеет не ссылочный тип: » + ИмяЭлемента;
                    КонецЕсли;
                   
ИмяЭлемента = МассивИмен[i];
                   
i=i+1;
                    Прервать;
                ИначеЕсли
i+1 <= Колич_Имен Тогда
                   
МассивИмен[i+1] = МассивИмен[i] + «_» + МассивИмен[i+1];
                Иначе
                    ВызватьИсключение
«Возникла неизвестная ошибка. В таблице нет данных о имени: » + ИмяЭлемента;
                КонецЕсли;
            КонецЦикла;

            //Выполняем построение адреса реквизита по которому нужно выполнить отбор или сортировку
           
АдресРеквизита = «»;
           
МетаВремЗначение = ВремОбъект.Метаданные();
            Пока
i <= Колич_Имен Цикл
               
ВремЗначение = МетаВремЗначение.Реквизиты.Найти(МассивИмен[i]);
                Если НЕ
ВремЗначение = Неопределено Тогда
                   
АдресРеквизита = АдресРеквизита + МассивИмен[i];
                   
формироватьАдресРеквизита(i, Колич_Имен, МетаВремЗначение, ВремЗначение, АдресРеквизита);
                Иначе
                    Попытка
                       
ВремЗначение = МетаВремЗначение.СтандартныеРеквизиты[МассивИмен[i]];
                       
АдресРеквизита = АдресРеквизита + МассивИмен[i];
                       
формироватьАдресРеквизита(i, Колич_Имен, МетаВремЗначение, ВремЗначение, АдресРеквизита);
                    Исключение
                       
МассивИмен[i+1] = МассивИмен[i] + «_» + МассивИмен[i+1];
                    КонецПопытки;
                КонецЕсли;
               
i=i+1;
            КонецЦикла;

            Если Отбор Тогда
               
ДобавитьОтборПоЗначению(КомпоновщикНастроек, ИмяЭлемента + ?(ПустаяСтрока(АдресРеквизита), «», «.» + АдресРеквизита), ПолучитьЗначениеРеквизита(АдресРеквизита, ВремОбъект));
               
ОбновитьИсториюОтборов(КомпоновщикНастроек, ИсторияОтборов);
            Иначе
               
ДобавитьСортировку(КомпоновщикНастроек, ИмяЭлемента + ?(ПустаяСтрока(АдресРеквизита), «», «.» + АдресРеквизита), Сортировка);
            КонецЕсли;
        КонецЕсли;
    КонецЕсли;

    //3. готовим макет
   
КомпоновщикМакетаДанных = Новый КомпоновщикМакетаКомпоновкиДанных;
   
МакетКомпоновкиДанных = КомпоновщикМакетаДанных.Выполнить(СхемаКомпоновкиДанных, КомпоновщикНастроек.Настройки, , , Тип(«ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений»));

    //4. исполняем макет
   
ПроцессорКомпоновкиДанных = Новый ПроцессорКомпоновкиДанных;
   
ПроцессорКомпоновкиДанных.Инициализировать(МакетКомпоновкиДанных);

    //5. выводим результат
   
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений;
   
ТаблицаНоменклатуры.Загрузить(ПроцессорВывода.Вывести(ПроцессорКомпоновкиДанных));
КонецПроцедуры

&НаСервере
Процедура ДобавитьСортировку(КомпоновщикНастроек, ИмяЭлемента, Направление)
   
ЭлементыПорядка = КомпоновщикНастроек.Настройки.Порядок.Элементы;
   
ЭлементыПорядка.Очистить();
   
ЭлементПорядка = ЭлементыПорядка.Добавить(Тип(«ЭлементПорядкаКомпоновкиДанных»));
   
ЭлементПорядка.Использование = Истина;
   
ЭлементПорядка.ТипУпорядочивания = Направление;
   
ЭлементПорядка.Поле = Новый ПолеКомпоновкиДанных(ИмяЭлемента);
КонецПроцедуры

&НаСервере
Процедура ДобавитьОтборПоЗначению(КомпоновщикНастроек, ИмяЭлемента, Значение)
    Перем
ЭлементОтбораНайден;
   
ЭлементыОтбора = КомпоновщикНастроек.Настройки.Отбор.Элементы;
    Для Каждого
ЭлементОтбора Из ЭлементыОтбора Цикл
       
ЭлементОтбора.Представление = ЭлементОтбора.ЛевоеЗначение;
        Если
ЭлементОтбора.Представление = ИмяЭлемента И ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно Тогда
           
ЭлементОтбора.Использование = НЕ ЭлементОтбора.Использование;
           
ЭлементОтбора.ПравоеЗначение = Значение;
           
ЭлементОтбораНайден = ЭлементОтбора;
        КонецЕсли;
    КонецЦикла;

    Если ЭлементОтбораНайден = Неопределено Тогда
       
ЭлементОтбора = ЭлементыОтбора.Добавить(Тип(«ЭлементОтбораКомпоновкиДанных»));
       
ЭлементОтбора.Использование = Истина;
       
ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных(ИмяЭлемента);
       
ЭлементОтбора.Представление = ЭлементОтбора.ЛевоеЗначение;
       
ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
       
ЭлементОтбора.ПравоеЗначение = Значение;
    КонецЕсли;
КонецПроцедуры

&НаСервере
Процедура ОбновитьИсториюОтборов(КомпоновщикНастроек, ИсторияОтборов)
   
//Создаем уникальное имя команды, УникальныйИдентификатор не всегда начинается с буквы, добавляем вначале «n»
   
ИмяКоманды = «n» + СтрЗаменить(Новый УникальныйИдентификатор, «-«, «»);
   
МассивОтборов = Новый Массив;
   
ЭлементыОтбора = КомпоновщикНастроек.Настройки.Отбор.Элементы;
    Для Каждого
ЭлементОтбора Из ЭлементыОтбора Цикл
        Если
ЭлементОтбора.Использование Тогда
           
МассивОтборов.Добавить(Новый Структура(«ЛевоеЗначение, ВидСравнения, ПравоеЗначение», ЭлементОтбора.ЛевоеЗначение, ЭлементОтбора.ВидСравнения, ЭлементОтбора.ПравоеЗначение));
        КонецЕсли;
    КонецЦикла;

    Если МассивОтборов.Количество() Тогда
       
ПредставлениеОтбора = ПолучитьПредставлениеОтбора(МассивОтборов);
       
КоличествоЭлементов = ИсторияОтборов.Количество()-1;
        Для
i=0 По КоличествоЭлементов Цикл
           
//Если отбор найден перемещаем команду в начало списка, так же в списке значений изменяем положение отбора
           
Если ПредставлениеОтбора = ИсторияОтборов[i].Представление Тогда
               
ПереместитьКомандуФормы(ИсторияОтборов[i].Значение.ИмяКоманды, ИсторияОтборов[0].Значение.ИмяКоманды);
               
ИсторияОтборов.Сдвинуть(i, —i);
                Прервать;
           
//Это новый элемент создаем вначале списка значений, так же команду устанавливаем вначало списка
           
ИначеЕсли i = КоличествоЭлементов Тогда
               
ДобавитьКомандуКФорме(ИмяКоманды, ПредставлениеОтбора, ИсторияОтборов[0].Значение.ИмяКоманды);
               
ИсторияОтборов.Вставить(0, Новый Структура(«ИмяКоманды, МассивОтборов», ИмяКоманды, МассивОтборов), ПредставлениеОтбора);
            КонецЕсли;
        КонецЦикла;
       
//Элементов еще нет, создаем первые элементы
       
Если КоличествоЭлементов < 0 Тогда
           
ДобавитьКомандуКФорме(ИмяКоманды, ПредставлениеОтбора);
           
ИсторияОтборов.Вставить(0, Новый Структура(«ИмяКоманды, МассивОтборов», ИмяКоманды, МассивОтборов), ПредставлениеОтбора);
        КонецЕсли;
    КонецЕсли;

    //Элементов больше 20, удаляем лишнее
   
Если ИсторияОтборов.Количество() = 21 Тогда
       
УдалитьКомандуФормы(ИсторияОтборов[20].Значение.ИмяКоманды);
       
ИсторияОтборов.Удалить(20);
    КонецЕсли;
КонецПроцедуры

&НаСервере
Функция ПолучитьПредставлениеОтбора(МассивОтборов)
   
ПредставлениеОтбора = «»;
   
КоличествоЭлементов = МассивОтборов.Количество()-1;
    Для
i=0 По КоличествоЭлементов Цикл
       
ПредставлениеОтбора = ПредставлениеОтбора + МассивОтборов[i].ЛевоеЗначение  + » «
                                                 
+ МассивОтборов[i].ВидСравнения   + » «
                                                 
+ МассивОтборов[i].ПравоеЗначение + ?(i<КоличествоЭлементов, «, «, «»);
    КонецЦикла;
    Возврат
ПредставлениеОтбора;
КонецФункции

&НаСервере
Процедура ДобавитьКомандуКФорме(ИмяКоманды, Представление, ИмяПозицииВставки = Неопределено)
   
Команда = Команды.Добавить(ИмяКоманды);
   
Команда.Действие = «ОтборИстория»;
   
Команда.Заголовок = Представление;
   
КомандаФормы = Элементы.Вставить(Команда.Имя, Тип(«КнопкаФормы»), Элементы.ИсторияОтборов, Элементы.Найти(ИмяПозицииВставки));
   
КомандаФормы.ИмяКоманды = Команда.Имя;
   
КомандаФормы.Заголовок  = Представление;
   
КомандаФормы.Вид  = ВидКнопкиФормы.КнопкаКоманднойПанели;
КонецПроцедуры

&НаСервере
Процедура ПереместитьКомандуФормы(ИмяКоманды, ИмяПозицииПеремещения)
   
Элементы.Переместить(Элементы.Найти(ИмяКоманды), Элементы.ИсторияОтборов, Элементы.Найти(ИмяПозицииПеремещения));
КонецПроцедуры

&НаСервере
Процедура УдалитьКомандуФормы(ИмяКоманды)
   
Элементы.Удалить(Элементы.Найти(ИмяКоманды));
   
Команды.Удалить(Команды.Найти(ИмяКоманды));
КонецПроцедуры

&НаСервере
Функция ПолучитьЗначениеРеквизита(АдресРеквизита, Объект)
    Перем
ЗначениеРеквизита;
    Выполнить(
«ЗначениеРеквизита = Объект.» + АдресРеквизита + «;»);
    Возврат
ЗначениеРеквизита;
КонецФункции

&НаСервере
Функция ПолучитьМассивИмен(ИмяЭлемента)
   
МассивСлов = Новый Массив;
   
ЧислоВхождений = СтрЧислоВхождений(ИмяЭлемента, «_»);
    Если
ЧислоВхождений = 0 Тогда
       
МассивСлов.Добавить(ИмяЭлемента);
    Иначе
        Для
Итератор = 0 По ЧислоВхождений 1 Цикл
           
Разделитель = Найти(ИмяЭлемента, «_»);
           
МассивСлов.Добавить(Лев(ИмяЭлемента, Разделитель 1));
           
ИмяЭлемента = Прав(ИмяЭлемента, СтрДлина(ИмяЭлемента) — Разделитель);
        КонецЦикла;
       
МассивСлов.Добавить(ИмяЭлемента);
    КонецЕсли;
    Возврат
МассивСлов;
КонецФункции

&НаСервере
Процедура формироватьАдресРеквизита(i, Колич_Имен, МетаВремЗначение, ВремЗначение, АдресРеквизита)
    Если
i + 1 <= Колич_Имен Тогда
       
//Из описания типа получаем метаданные
       
МетаВремЗначение = ВремЗначение.Тип.ПривестиЗначение(Неопределено).Метаданные();
       
АдресРеквизита = АдресРеквизита + «.»;
    КонецЕсли;
КонецПроцедуры

&НаКлиенте
Процедура ОбновитьДанныеОтбора(ОтключитьОтбор = Ложь)
   
Элементы.ОтборПоЗначению.Пометка = Ложь;
   
Элементы.ОтборИСортировка.Пометка = Ложь;
    Для Каждого
Элемент Из КомпоновщикНастроек.Настройки.Отбор.Элементы Цикл
        Если
ОтключитьОтбор Тогда Элемент.Использование = Ложь; КонецЕсли;
        Если
Элемент.Использование И Элемент.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно Тогда
           
Элементы.ОтборПоЗначению.Пометка = Истина;
        ИначеЕсли
Элемент.Использование Тогда
           
Элементы.ОтборИСортировка.Пометка = Истина;
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

&НаКлиенте
Процедура ОтборИСортировка(Команда)
   
Результат = ОткрытьФормуМодально(«ВнешняяОбработка.УниверсальныйОтбор.Форма.ФормаНастройки», Новый Структура(«КомпоновщикНастроек», КомпоновщикНастроек), ЭтаФорма);
    Если
ТипЗнч(Результат) = Тип(«КомпоновщикНастроекКомпоновкиДанных») Тогда
       
КомпоновщикНастроек = Результат;
       
ОбновитьДанныеОтбора();
       
ОбновитьИсториюОтборов(КомпоновщикНастроек, ИсторияОтборов);
       
ТСтрока = Элементы.ИерархияНоменклатуры.ТекущаяСтрока;
        Если НЕ
ТСтрока.Пустая() Тогда СформироватьКлиент(ТСтрока); КонецЕсли;
    КонецЕсли;
КонецПроцедуры

&НаКлиенте
Процедура ОтборПоЗначению(Команда)
   
ТСтрока  = Элементы.ИерархияНоменклатуры.ТекущаяСтрока;
   
ТДанные  = Элементы.ТаблицаНоменклатуры.ТекущиеДанные;
   
ТЭлемент = Элементы.ТаблицаНоменклатуры.ТекущийЭлемент;
    Если НЕ
ТСтрока.Пустая() И НЕ Элементы.ТаблицаНоменклатуры.ТекущиеДанные = Неопределено Тогда
       
ИмяЭлемента = ТЭлемент.Имя;
       
СформироватьКлиент(ТСтрока, Истина, , ТДанные.ПолучитьИдентификатор(), ИмяЭлемента);
    КонецЕсли;
КонецПроцедуры

&НаКлиенте
Процедура ОтключитьОтбор(Команда)
   
ОбновитьДанныеОтбора(Истина);
   
ТСтрока = Элементы.ИерархияНоменклатуры.ТекущаяСтрока;
    Если НЕ
ТСтрока.Пустая() Тогда СформироватьКлиент(ТСтрока); КонецЕсли;
КонецПроцедуры

&НаКлиенте
Процедура ОтборИстория(Команда)
   
//Ищем в истории отборов отбор соответствующий имени команды
   
Перем МассивОтборов;
    Для
i=0 По ИсторияОтборов.Количество()-1 Цикл
        Если
ИсторияОтборов[i].Значение.ИмяКоманды = Команда.Имя Тогда
           
МассивОтборов = ИсторияОтборов[i].Значение.МассивОтборов;
           
ПереместитьКомандуФормы(Команда.Имя, ИсторияОтборов[0].Значение.ИмяКоманды);
            Если
ИсторияОтборов.Количество() > 1 Тогда ИсторияОтборов.Сдвинуть(i, —i); КонецЕсли;
            Прервать;
        КонецЕсли;
    КонецЦикла;

    //Обнуляем все отборы, перед установкой отбора из истории отборов
   
ЭлементыОтбора = КомпоновщикНастроек.Настройки.Отбор.Элементы;
    Для Каждого
Элемент Из ЭлементыОтбора Цикл Элемент.Использование = Ложь; КонецЦикла;
   
//Устанавливаем отборы
   
Для i=0 По МассивОтборов.Количество()-1 Цикл
       
ОтборИзМассиваОпределен = Неопределено;
        Для Каждого
Элемент Из ЭлементыОтбора Цикл
            Если
Элемент.ЛевоеЗначение  = МассивОтборов[i].ЛевоеЗначение
              И  Элемент.ВидСравнения   = МассивОтборов[i].ВидСравнения Тогда
               
Элемент.ПравоеЗначение  = МассивОтборов[i].ПравоеЗначение;
               
Элемент.Использование   = Истина;
               
ОтборИзМассиваОпределен = Истина;
                Прервать;
            КонецЕсли;
        КонецЦикла;
       
//Возможно была очистка отборов вручную, значит создаем нужный отбор
       
Если ОтборИзМассиваОпределен = Неопределено Тогда
           
ЭлементОтбора = ЭлементыОтбора.Добавить(Тип(«ЭлементОтбораКомпоновкиДанных»));
           
ЭлементОтбора.Использование = Истина;
           
ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных(МассивОтборов[i].ЛевоеЗначение);
           
ЭлементОтбора.Представление = МассивОтборов[i].ЛевоеЗначение;
           
ЭлементОтбора.ВидСравнения  = МассивОтборов[i].ВидСравнения;
           
ЭлементОтбора.ПравоеЗначение = МассивОтборов[i].ПравоеЗначение;
        КонецЕсли;
    КонецЦикла;

    //Выполняем запрос
   
ТСтрока = Элементы.ИерархияНоменклатуры.ТекущаяСтрока;
    Если НЕ
ТСтрока.Пустая() Тогда
       
СформироватьКлиент(ТСтрока);
    КонецЕсли;
КонецПроцедуры

&НаКлиенте
Процедура СортироватьПоВозрастанию(Команда)
   
ТСтрока  = Элементы.ИерархияНоменклатуры.ТекущаяСтрока;
   
ТДанные  = Элементы.ТаблицаНоменклатуры.ТекущиеДанные;
   
ТЭлемент = Элементы.ТаблицаНоменклатуры.ТекущийЭлемент;
    Если НЕ
ТСтрока.Пустая() И НЕ Элементы.ТаблицаНоменклатуры.ТекущиеДанные = Неопределено Тогда
       
ИмяЭлемента = ТЭлемент.Имя;
       
СформироватьКлиент(ТСтрока, , НаправлениеСортировкиКомпоновкиДанных.Возр, ТДанные.ПолучитьИдентификатор(), ИмяЭлемента);
    КонецЕсли;
КонецПроцедуры

&НаКлиенте
Процедура СортироватьПоУбыванию(Команда)
   
ТСтрока  = Элементы.ИерархияНоменклатуры.ТекущаяСтрока;
   
ТДанные  = Элементы.ТаблицаНоменклатуры.ТекущиеДанные;
   
ТЭлемент = Элементы.ТаблицаНоменклатуры.ТекущийЭлемент;
    Если НЕ
ТСтрока.Пустая() И НЕ Элементы.ТаблицаНоменклатуры.ТекущиеДанные = Неопределено Тогда
       
ИмяЭлемента = ТЭлемент.Имя;
       
СформироватьКлиент(ТСтрока, , НаправлениеСортировкиКомпоновкиДанных.Убыв, ТДанные.ПолучитьИдентификатор(), ИмяЭлемента);
    КонецЕсли;
КонецПроцедуры

27 Comments

  1. pbazeliuk

    Причиной этого труда стало: отсутствие привычной кнопки «Отбор по значению в текущей колонке», некоторые проблемы с динамическими списками, отсутствие истории отборов, авто восстановления настроек отборов при перезапуске формы (динамических списков), а так же стремление увеличить функциональность отборов и сортировок с учетом возможностей управляемых форм.

    Перейти к публикации

    Reply
  2. zavedeev

    Отлично. Спасибо!!!

    Reply
  3. afanasko

    Отличная вещь! Побежал прикручивать к своим конфам.

    Reply
  4. dandrontiy

    Очень интересно. Получается не только чисто отбор можно использовать, но еще и дополнительные запросы.

    Функционал явно превосходит механизм отборов в 1с 8.1

    Так можно подумать и добавить спец запросы (сделанные не пользователем, а разрабочиком и прикрученные к механизму отбора) а пользователь будет задавать только конечные параметры. Например отбор по реквизитам подчиненного документа.

    Плюс однозначно!

    Но с кодом еще придется поразбираться 😉 не тривиально всё.

    Reply
  5. Saipl

    Работа проделана конечно большая и это +, надеюсь что данный сервис появится на уровне платформы (то что до сих пор не появился это -)

    Reply
  6. khaoos

    Хорошая серьезная разработка. Автор молодец. Однозначно плюс, к тому же еще и код выложил!

    Reply
  7. gavrikprog

    делете

    Reply
  8. xzorkiix
    2. Отсутсвует ошибка при использовании истории отборов (в 1С Предприятии 8.1 если установлен отбор и воспользоватся отбором из истории текущий отбор не отменяется);

    Не знал даже этого.

    Reply
  9. aviaye

    Очень этого не хватало, спасибо автору) И пошла пробовать-экспериментировать

    Reply
  10. Den_D

    Вот это штукенция очень надо. Спасибо огромное!

    Reply
  11. An-Aleksey

    То что доктор прописал 🙂 Однозначно +

    Reply
  12. nizar

    Офигенно

    Reply
  13. Bober777

    МОЛОДЦА

    Reply
  14. Yashazz

    Красиво, но для добавляемых колонок нежизнеспособно, ибо сделать такой универсал очень трудно.

    Вот есть у меня динам.список по выборке, а выборка строится с использованием механизма характеристик. И вот хочу я отобрать по колонке, принудительно выведенной на интерфейс. И тут, подозреваю, нифига не выйдет.

    Да, и если в именах полей, сами по себе, есть знаки подчёркивания — тоже сомневаюсь в безошибочности.

    Reply
  15. pbazeliuk

    (13) Yashazz, Подчеркивания обрабатываются вот этим куском, если это добавленая колонка, тогда поиск идет по метаданным на совпадение (В случае, когда в метаданных есть «Полное_Наименование» оно обработается правильно). Проблема присутствует, если в выборке множество реквизитов ссылочного типа, а не один.

    Пока i <= Колич_Имен Цикл

    ВремЗначение = МетаВремЗначение.Реквизиты.Найти(МассивИмен[i]);

    Если НЕ ВремЗначение = Неопределено Тогда

    АдресРеквизита = АдресРеквизита + МассивИмен[i];

    формироватьАдресРеквизита(i, Колич_Имен, МетаВремЗначение, ВремЗначение, АдресРеквизита);

    Иначе

    Попытка

    ВремЗначение = МетаВремЗначение.СтандартныеРеквизиты[МассивИмен[i]];

    АдресРеквизита = АдресРеквизита + МассивИмен[i];

    формироватьАдресРеквизита(i, Колич_Имен, МетаВремЗначение, ВремЗначение, АдресРеквизита);

    Исключение

    МассивИмен[i+1] = МассивИмен[i] + «_» + МассивИмен[i+1];

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

    КонецЕсли;

    i=i+1;

    КонецЦикла;

    Почти все нюансы эти уже исправлены, но руки не доходят обновить публикацию.

    Reply
  16. m1kll

    спасибо, автор молодец

    Reply
  17. tommyknocker

    Отличная идея. Пользователям жутко не хватает этих кнопок. Вроде как в УФ это и есть, но где раньше было одно нажатие, теперь нужно 2-3 в лучшем случае, а при составных отборах и того больше.

    Еще бы как-то это в общую команду оформить…

    Reply
  18. prodines

    Да как этим пользоваться, объясните… (для тех, кто управляемые формы видит в первый раз)

    У меня управляемая форма списка реализаций товаров и услуг. Основной реквизит — Список с типом ДинамическийСписок. Чекбокс Произвольный запрос установлен.

    В скаченной обработке среди реквизитов есть таблица значений. Значит, работаем вместо динамического списка с таблицей значений, что ли?

    И окна «Иерархия номенклатуры» у меня нет = значит, из программного кода придётся вырезать куски кода под него?

    Reply
  19. pbazeliuk

    (17) prodines, это как пример. Для динамического списка эта публикация не подойдет. Для динамического списка все совсем иначе и в описании еще написано:

    отсутствие привычной кнопки «Отбор по значению в текущей колонке», некоторые проблемы с динамическими списками, отсутствие истории отборов, авто восстановления настроек отборов при перезапуске формы (динамических списков)

    .

    Reply
  20. validat

    Скачал. Опыта маловато. Буду пробовать. Сортировка нужна в платформе, однозначно.

    Reply
  21. lesenoklenok

    Отличная статья! Очень помогла! Спасибо автору!

    Reply
  22. IDija

    Подскажите а как бы этот функционал использовать в форме выбора? Чтобы возвращало значение?

    Reply
  23. pbazeliuk

    (21) IDija, можете детально описать проблему, не понятно зачем это использовать в форме выбора?

    Reply
  24. IDija

    (22) pbazeliuk, В документе при выборе в ТЧ Номенклатуры нет истории предыдущего выбора. Что бы при написании наименования предлагалась предыдущие варианты поиска.

    Может есть и вариант попроще, но не шел?

    Reply
  25. pbazeliuk

    (23) IDija, историю выбора номенклатуры нужно реализовывать самому. Задача по своей сути очень простая, если не нужно использовать переопределение вызовов и динамическое подключение функциональности.

    Reply
  26. Manticor

    Подскажите пожалуйста, возможно ли данный механизм реализовать под обычные формы для табличного поля с типом таблица значений??

    Reply
  27. pbazeliuk

    (25) Manticor, для обычных форм можно использовать только идею, но не сам код что тут представлен, нужны множественные доработки.

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *