Имя: Пароль:
1C
1С v8
Универсальная асинхронная очистка ТЧ документа
0 destructor
 
24.12.15
15:34
С наступающим)
С приближением праздников голова работать желает все меньше, но грамотное решение вопроса хотелось бы отыскать:

Итак, на форме есть несколько элементов (полей ввода, назовем их реквизитами шапки) и несколько табличных частей. Часть полей ввода отображаемых на форме связано с реквизитами формы, другая часть - с реквизитами объекта. При изменении значения реквизита шапки необходимо, при наличии записей в ТЧ, предложить пользователю очистить табличные части, в случае согласия - очистить и значение реквизита соответствующим образом изменить, при отказе оставить табличные части как есть, а значение реквизита вернуть к начальному  (т.е. как будто никто ничего не менял) и в зависимости от ответа пользователя продолжить выполнение действий в обработке события. В общем ситуация абсолютно стандартная)), только сделать надо асинхронно, и процедура очистки табличной части должна быть одна для всех ситуаций. И процедуру возврата к старому значению реквизита (в случае отказа пользователя от очистки) сделать тоже более менее универсальную  (чтоб не писать обработчики оповещения "ПослеДиалога" для каждого элемента формы)

Вот процедура изменения одного из реквизитов:

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

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

И процедуры очистки:

&НаКлиенте
Процедура ПодготовитьТабличныеЧастиКЗаполнениюНаКлиенте(Отказ)
    
    СтруктураТЧ = Новый Структура;
    
    Если Объект.Начисления.Количество() Тогда
        СтруктураТЧ.Вставить("Начисления", "Начисления сотрудников");
    КонецЕсли;
    
    Если Объект.НачисленияПоВыработке.Количество() Тогда
        СтруктураТЧ.Вставить("НачисленияПоВыработке", "Начисления по выработке сотрудников");
    КонецЕсли;
    
    Если Не СтруктураТЧ.Количество() Тогда
        Возврат;
    КонецЕсли;
    
    Отказ = Истина; //если что-то есть то отказываем, т.к. дальше вся обработка пойдет в оповещении, а нам флаг обязательно нужно вернуть из этой процедуры
                    //если вызвать процедуру повторно, то тч будут пустыми, значит отказ не сработает и обработка пройдет штатно
    ПараметрыОповещения = Новый Структура;
    ПараметрыОповещения.Вставить("СтруктураТЧКОчистке", СтруктураТЧ);
    
    ОписаниеОповещения = Новый ОписаниеОповещения("ПодготовитьТабличныеЧастиКЗаполнениюПослеДиалога", ЭтаФорма, ПараметрыОповещения);
    ТекстВопроса = ?(СтруктураТЧ.Количество() = 1, "Табличная часть ", "Табличные части: ");
    
    Для Каждого КлючИЗначение Из СтруктураТЧ Цикл
        ТекстВопроса = ТекстВопроса + """" + КлючИЗначение.Значение + """" + ?(СтруктураТЧ.Количество() = 1, "", "; ");
    КонецЦикла;
    
    ТекстВопроса = ТекстВопроса + ?(СтруктураТЧ.Количество() = 1, "будет очищена. Продолжить?", "будут очищены. Продолжить?");
    ПоказатьВопрос(ОписаниеОповещения, ТекстВопроса, РежимДиалогаВопрос.ДаНет, , , "В табличных частях документа есть записи", );
    
КонецПроцедуры

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

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

т.е. если в табличных частях есть записи то отказ всегда взведется в истину, появится вопрос и если на него ответили положительно то табличные части очистятся а реквизит "ПериодРасчета" останется НЕ измененным. Если после этого опять попытаться изменить ПериодРасчета, то так как табличные уже пустые вопросов не будет, отказ = Ложь, и реквизит изменит свое значение на новое.

Т.е. в принципе задача почти решена, только "ПериодРасчета" при наличии записей в ТЧ нужно регулировать дважды. После первого раза он как был, например "Декабрь 2015" так и останется, только ТЧ очистятся... после второго раза он перещелкнется на "Январь 2016".

Вопрос как сделать так чтобы в случае отказа от очистки реквизит оставался неизменным, а в случае согласия принимал новое значение? При этом, напоминаю, нельзя писать обработчики оповещения для очистки ТЧ для каждого элемента свой. Процедура ПодготовитьТабличныеЧастиКЗаполнениюНаКлиенте(Отказ) должна вызывать для всех элементов формы и быть универсальной.
1 destructor
 
24.12.15
15:43
у меня собственно, родилось вот такое кривое решение...
в обработку очистки передавать описание метода который необходимо вызвать повторно, т.е. первый раз мы чистим ТЧ и оставляем реквизит неизменным, тут же вызываем обработку изменения еще раз и т.к. тч уже чистые то обработка очистки не сработает отказ останется равным ложь и реквизит изменит свое значение.

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

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

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


&НаКлиенте
Процедура ПодготовитьТабличныеЧастиКЗаполнениюПослеДиалога(Результат, ПараметрыОповещения) Экспорт
    
    Если Результат = КодВозвратаДиалога.Нет Тогда
        Возврат;
    КонецЕсли;
    
    Для Каждого КлючИЗначение Из ПараметрыОповещения.СтруктураТЧКОчистке Цикл
        Объект[КлючИЗначение.Ключ].Очистить();
    КонецЦикла;
    
    #Если НЕ ВебКлиент Тогда
        
        ОписаниеМетода = Неопределено;
        Если НЕ ПараметрыОповещения.Свойство("ПараметрыПовторногоВызова", ОписаниеМетода) Тогда
            Возврат;
        КонецЕсли;
        
        ПредставлениеМетода = ОписаниеМетода.ИмяМетода;
        ПараметрыМетода = ОписаниеМетода.Параметры;
        ПараметрыМетодаСтрока = "(";
        КоличествоПараметров = 0;
        
        Для Каждого ИмяИЗначениеПараметра Из ПараметрыМетода Цикл
            КоличествоПараметров = КоличествоПараметров + 1;
            ПараметрыМетодаСтрока = ПараметрыМетодаСтрока + "ПараметрыМетода." + ИмяИЗначениеПараметра.Ключ;
            Если КоличествоПараметров < ПараметрыМетода.Количество() Тогда
                ПараметрыМетодаСтрока = ПараметрыМетодаСтрока + ",";
            КонецЕсли;
        КонецЦикла;
        
        ПараметрыМетодаСтрока = ПараметрыМетодаСтрока + ")";
        
        Выполнить ПредставлениеМетода + ПараметрыМетодаСтрока;
        
    #КонецЕсли

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

кто-нибудь знает как это сделать красивее? )) Понимаю что текста много, но вдруг кого заинтересует вопрос))
2 Лефмихалыч
 
24.12.15
15:45
(0) перед началом изменения твоего реквизита запоминай его предыдущее значение, чтобы в асинхронном обработчике при отказе вернуть обратно
3 destructor
 
24.12.15
15:54
(2) Да, это простой вариант и наверное правильный, но тогда для каждого элемента придется писать свои обработчики оповещения? Т.е. у меня 8 реквизитов шапки перед изменением которых нужно чистить ТЧ. Часть из них реквизиты объекта, часть - формы. Т.е. перед очисткой мне нужно понимать какой из реквизитов инициировал эту очистку, знать его старое значение и тогда в оповещении , если пользователь отказался вернуть ему значение. Пункт про универсальность обработки выпадает ))
4 zenik
 
24.12.15
18:00
(3) Запоминай состояние ВСЕХ своих реквизитов, и в случае отказа - возвращай значения всех на место. А знать, какой меняли - совсем не обязательно.