Здравствуйте.
В данной статье я хочу рассказать о своем опыте работы с настройками в 1С – их представлении и сохранении. Этот способ особенно актуален для внешних обработок и отчетов, которые либо не завязаны на конкретную конфигурацию, либо просто не хотят хранить свои настройки в каких-либо объектах конфигурации. Никаких особых технических открытий предлагаемый способ не содержит, просто он делает более переносимым и упорядоченным применение стандартных решений – вся нудная и кропотливая работа может быть проделана единожды, а затем полученный шаблон можно с минимальными изменениями использовать во всех своих проектах. Суть метода как раз в этом.

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

А что если один единственный раз создать инструмент для работы с настройками – универсальный и переносимый? Так, чтобы его можно было легко, не задумываясь копировать между своими программами (ну естественно изменяя собственно сам набор конкретных параметров). Попробуем…

В реализации будем использовать описанный ранее технический прием «самодельного ООП в 1С». Создадим в виде отдельного класса хранилище настроек программы (если нужно как-то обособить группы настроек, то программа может иметь несколько таких классов-хранилищ). Стандартные вызовы (ВосстановитьЗначение, СохранитьЗначение) будет использоваться один раз за всю программу, т.к. все содержимое нашего хранилища будет сериализовано в XML-формат. Таким образом, можно обеспечить представление разветвленной структуры, а не просто «плоский набор» значений (по типу INI-файлов). В нашем примере, однако, будем рассматривать тот самый «плоский набор» для упрощения, т.к. структура набора принципиального значения не имеет.

К примеру, пусть у нас имеется следующий набор параметров:
Название Тип Начальное значение
Парам1 Число 0
Парам2 Строка «»
Парам3 СправочникСсылка.Номенклатура Неопределено
Парам4 Булево Ложь
Парам5 Дата Неопределено

Условно рассматриваем только простейшие типы, чтобы не привязываться ни к каким конкретным конфигурациям. Но также рассмотрим и ссылочный тип (Справочник «Номенклатура» есть во многих типовых конфигурациях), чтобы показать идею сериализации в строку и восстановления из строки более сложного объекта.

Структура полей класса будет выглядеть следующим образом:
Функция НастрПрогр_СоздатьОбъект()

	НастрПрогр = Новый Структура;
	НастрПрогр.Вставить("ChangeInfo", Ложь);     // Признак наличия несохраненных изменений в наборе
	НастрПрогр.Вставить("ErrMsg", "");           // Сообщение о последней ошибке
	// Общие параметры, хранящиеся в настройках
	НастрПрогр.Вставить("Set_Парам1", Неопределено); // Параметр настроек 1
	НастрПрогр.Вставить("Set_Парам2", Неопределено); // Параметр настроек 2
	НастрПрогр.Вставить("Set_Парам3", Неопределено); // Параметр настроек 3
	НастрПрогр.Вставить("Set_Парам4", Неопределено); // Параметр настроек 4
	НастрПрогр.Вставить("Set_Парам5", Неопределено); // Параметр настроек 5

	Возврат НастрПрогр;

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

Как видим, кроме непосредственно целевых параметров, в составе класса есть и служебные поля. Целевые поля имеют специальное соглашение в наименовании – начинаются с префикса «Set_». Это нужно, для того чтобы автоматически отличать целевые поля от служебных при обходе полей структуры (имитирующей объект класса) в цикле. Снаружи эти изменения в именах не видны и используются обычные названия параметров (без префикса «Set_»).

Теперь приведем код данного класса полностью:
Класс НастройкиПрограммы
////////////////////////////////////////////////////////////////////////////////
// Реализация класса НастройкиПрограммы (НастрПрогр)

// Создание полей объекта в виде структуры
//
// Параметры:
//  Нет.
// Возврат:
//  Возвращает созданную структуру
//
Функция НастрПрогр_СоздатьОбъект() Экспорт
	
	НастрПрогр = Новый Структура;
	НастрПрогр.Вставить("ChangeInfo", Ложь);     // Признак наличия несохраненных изменений в наборе
	НастрПрогр.Вставить("ErrMsg", "");           // Сообщение о последней ошибке
	// Общие параметры, хранящиеся в настройках
	НастрПрогр.Вставить("Set_Парам1", Неопределено); // Параметр настроек 1
	НастрПрогр.Вставить("Set_Парам2", Неопределено); // Параметр настроек 2
	НастрПрогр.Вставить("Set_Парам3", Неопределено); // Параметр настроек 3
	НастрПрогр.Вставить("Set_Парам4", Неопределено); // Параметр настроек 4
	НастрПрогр.Вставить("Set_Парам5", Неопределено); // Параметр настроек 5

	Возврат НастрПрогр;
	
КонецФункции

// Имитирует конструктор объекта
//
// Параметры:
//  Нет.
// Возврат:
//  (Структура) - Структура с полями объекта
//
Функция НастрПрогр_Конструктор() Экспорт
	
	НастрПрогр = НастрПрогр_СоздатьОбъект();
	// Инициализируем поля объекта
	НастрПрогр_SetDefAttr(НастрПрогр);
	
	Возврат НастрПрогр;
	
КонецФункции

// Имитирует деструктор объекта - освобождает память
//
// Параметры:
//  НастрПрогр - ссылка на объект
//
Процедура НастрПрогр_Деструктор(НастрПрогр) Экспорт
	
	
КонецПроцедуры

// Инициализирует атрибуты объекта значениями по умолчанию.
//
// Параметры:
//  НастрПрогр - ссылка на объект
//
Процедура НастрПрогр_SetDefAttr(НастрПрогр) Экспорт
	
	НастрПрогр.ErrMsg = "";
	НастрПрогр.Set_Парам1 = 0;
	НастрПрогр.Set_Парам2 = "";
	НастрПрогр.Set_Парам3 = Неопределено;
	НастрПрогр.Set_Парам4 = Ложь;
	НастрПрогр.Set_Парам5 = Неопределено;
	
КонецПроцедуры

// Копирует значения полей объекта НастрПрогр2 в текущий НастрПрогр1.
// Все предыдущие значения из НастрПрогр1 будут утеряны.
//
// Параметры:
//  НастрПрогр1 - ссылка на объект
//  НастрПрогр2 - ссылка на другой копируемый объект
//
Процедура НастрПрогр_Assign(НастрПрогр1, НастрПрогр2) Экспорт
	
	Если (НастрПрогр1 <> Неопределено) И
		 (НастрПрогр2 <> Неопределено) И
		 (НастрПрогр_IsEqual(НастрПрогр1, НастрПрогр2) = Ложь) Тогда
		Для Каждого Поле Из НастрПрогр1 Цикл
			Если Найти(Поле.Ключ, "Set_") = 1 Тогда
				// Копируем только значения полей параметров (не служебные поля)
				НастрПрогр1[Поле.Ключ] = НастрПрогр2[Поле.Ключ]
			КонецЕсли
		КонецЦикла;			
		НастрПрогр1.ChangeInfo = Истина
	КонецЕсли
	 
КонецПроцедуры

// Сравнивает два набора параметров между собой.
//
// Параметры:
//  НастрПрогр1 - ссылка на объект
//  НастрПрогр2 - ссылка на другой сравниваемый объект
// Возврат
//  Истина, если объект НастрПрогр2 содержит теже данные, что и
//  текущий НастрПрогр1 и Ложь - в противном случае
//
Функция НастрПрогр_IsEqual(НастрПрогр1, НастрПрогр2) Экспорт
	
	Рез = Ложь;
	
	Если (НастрПрогр1 <> Неопределено) И
		 (НастрПрогр2 <> Неопределено) Тогда
		ФлагСравн = Истина;
		Для Каждого Поле Из НастрПрогр1 Цикл
			Если Найти(Поле.Ключ, "Set_") = 1 Тогда
				// Сравниваем только значения полей параметров (не служебные поля)
				Если Поле.Значение <> НастрПрогр2[Поле.Ключ] Тогда
					ФлагСравн = Ложь;
					Прервать
				КонецЕсли
			КонецЕсли
		КонецЦикла;
		Рез = ФлагСравн
	КонецЕсли;
	
	Возврат Рез
	
КонецФункции

// Инициализирует атрибуты объекта значениями по умолчанию.
//
// Параметры:
//  НастрПрогр - ссылка на объект
//
Функция НастрПрогр_GetErrorMsg(НастрПрогр) Экспорт
	
	Возврат НастрПрогр.ErrMsg
	
КонецФункции

// Возвращает значение параметра в наборе.
//
// Параметры:
//  НастрПрогр - ссылка на объект
//  PrmName - название параметра
// Возврат
//  Значение параметра PrmName или Неопределено, если такой параметр не найден
//
Функция НастрПрогр_GetPrm(НастрПрогр, PrmName) Экспорт
	
	Рез = Неопределено;
	НастрПрогр.ErrMsg = "";
	
	Попытка
		Рез = НастрПрогр["Set_" + PrmName];
	Исключение
		НастрПрогр.ErrMsg = "НастрПрогр_GetPrm: Не найден параметр: " + PrmName;
	КонецПопытки;
	
	Возврат Рез
	
КонецФункции

// Устанавливает значение параметра в наборе.
//
// Параметры:
//  НастрПрогр - ссылка на объект
//  PrmName - название параметра
//  PrmVal - устанавливаемое значение параметра
//
Процедура НастрПрогр_SetPrm(НастрПрогр, PrmName, PrmVal) Экспорт
	
	НастрПрогр.ErrMsg = "";
	
	Попытка
		Если НастрПрогр["Set_" + PrmName] <> PrmVal Тогда
			НастрПрогр["Set_" + PrmName] = PrmVal;
			НастрПрогр.ChangeInfo = Истина
		КонецЕсли
	Исключение
		НастрПрогр.ErrMsg = "НастрПрогр_SetPrm: Не найден параметр: " + PrmName;
	КонецПопытки
	
КонецПроцедуры

// Возвращает строковое значение указанного параметра (предварительно преобразуется в строку).
//
// Параметры:
//  НастрПрогр - ссылка на объект
//  PrmName - название параметра
// Возврат
//  Строковое значение параметра PrmName или Неопределено, если такой параметр не найден
//
Функция НастрПрогр_GetPrmStrVal(НастрПрогр, PrmName) Экспорт
	
	Рез = Неопределено;
	НастрПрогр.ErrMsg = "";
	
	Попытка
		ИсхЗнач = НастрПрогр["Set_" + PrmName];
		// Преобразование в зависимости от типа параметра
		Если PrmName = "Парам1" Тогда
			// Параметр настроек №1 (Число)
			Рез = Формат(ИсхЗнач, "ЧГ=0; ЧН=''")
		ИначеЕсли PrmName = "Парам2" Тогда
			// Параметр настроек №2 (Строка)
			Рез = ИсхЗнач
		ИначеЕсли PrmName = "Парам3" Тогда
			// Параметр настроек №3 (СправочникСсылка.Номенклатура)
			Если ЗначениеЗаполнено(ИсхЗнач) Тогда
				Рез = ИсхЗнач.Код
			Иначе
				Рез = Неопределено
			КонецЕсли
		ИначеЕсли PrmName = "Парам4" Тогда
			// Параметр настроек №4 (Булево)
			Рез = Формат(ИсхЗнач, "БЛ=0; БИ=1")
		ИначеЕсли PrmName = "Парам5" Тогда
			// Параметр настроек №5 (Дата)
			Рез = Формат(ИсхЗнач, "ДФ=""yyyyMMddHHmmss""")
		КонецЕсли
	Исключение
		НастрПрогр.ErrMsg = "НастрПрогр_GetPrmStrVal: Ошибка сериализации значения: " + PrmName + " : " + ИнформацияОбОшибке().Описание;
	КонецПопытки;
	
	Возврат Рез
	
КонецФункции

// Устанавливает значение параметра в наборе из переданного строкового значения
// (предварительно идет преобразование из строкового значения в нужное).
//
// Параметры:
//  НастрПрогр - ссылка на объект
//  PrmName - название параметра
//  StrPrmVal - строковое представление устанавливаемого значения параметра
//
Процедура НастрПрогр_SetPrmFromStrVal(НастрПрогр, PrmName, StrPrmVal) Экспорт
	
	НастрПрогр.ErrMsg = "";
	
	Попытка
		НовЗнач = Неопределено;
		// Преобразование в зависимости от типа параметра
		Если PrmName = "Парам1" Тогда
			// Параметр настроек №1 (Число)
			НовЗнач = Число(StrPrmVal)
		ИначеЕсли PrmName = "Парам2" Тогда
			// Параметр настроек №2 (Строка)
			НовЗнач = StrPrmVal
		ИначеЕсли PrmName = "Парам3" Тогда
			// Параметр настроек №3 (СправочникСсылка.Номенклатура)
			Если ЗначениеЗаполнено(StrPrmVal) Тогда
				НовЗнач = Справочники.Номенклатура.НайтиПоКоду(StrPrmVal);
				Если НЕ ЗначениеЗаполнено(НовЗнач) Тогда
					НовЗнач = Неопределено
				КонецЕсли
			КонецЕсли
		ИначеЕсли PrmName = "Парам4" Тогда
			// Параметр настроек №4 (Булево)
			НовЗнач = Булево(Число(StrPrmVal))
		ИначеЕсли PrmName = "Парам5" Тогда
			// Параметр настроек №5 (Дата)
			НовЗнач = Дата(StrPrmVal)
		КонецЕсли;
		// Установка значения
		Если НастрПрогр["Set_" + PrmName] <> НовЗнач Тогда
			НастрПрогр["Set_" + PrmName] = НовЗнач;
			НастрПрогр.ChangeInfo = Истина
		КонецЕсли
	Исключение
		НастрПрогр.ErrMsg = "НастрПрогр_SetPrmFromStrVal: Ошибка установки значения: " + PrmName + " : " + ИнформацияОбОшибке().Описание;
	КонецПопытки
	
КонецПроцедуры

// Возвращает признак наличия несохраненных изменений
// в наборе параметров
//
// Параметры:
//  НастрПрогр - ссылка на объект
// Возврат
//  Значение признака несохраненных изменений
//
Функция НастрПрогр_GetChangeInfo(НастрПрогр) Экспорт
	
	Возврат НастрПрогр.ChangeInfo
	
КонецФункции

// Принудительно устанавливает значение признака наличия несохраненных
// изменений в наборе параметров
//
// Параметры:
//  НастрПрогр - ссылка на объект
//  ChangeInfo - значение признака несохраненных изменений
//
Процедура НастрПрогр_SetChangeInfo(НастрПрогр, ChangeInfo) Экспорт
	
	НастрПрогр.ChangeInfo = ChangeInfo
	
КонецПроцедуры

// Загружает структуру из XML-документа, размещенного в объекте ЧтениеXML.
//
// Параметры:
//  НастрПрогр - ссылка на объект
//  ЧтениеXML - объект для чтения XML-документа
// Возврат
//  Истина, если загрузка прошла удачно и Ложь - в противном случае
//
Функция НастрПрогр_LoadSettingsFromXML(НастрПрогр, ЧтениеXML) Экспорт
	
	Рез = Ложь;  // Еще ничего загрузить не успели
	НастрПрогр.ErrMsg = "";
	
	Если ЧтениеXML <> Неопределено Тогда
		Попытка
			// Начальная инициализация
			НастрПрогр_SetDefAttr(НастрПрогр);
			
			// Процесс загрузки
			Началась_settings = Ложь;
			НазвПрм = "";
			Пока ЧтениеXML.Прочитать() Цикл
				Если ЧтениеXML.ЛокальноеИмя = "settings" Тогда
					Если (Началась_settings = Ложь) И
						 (ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента) Тогда
						// Началась секция с набором параметров
						Началась_settings = Истина
					Иначе
						// Закончилась секция с набором параметров
						Началась_settings = Ложь;
						НазвПрм = "";
						Прервать
					КонецЕсли
				Иначе
					Если Началась_settings Тогда
						// Если находимся в наборе параметров
						Если ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента Тогда
							// Пробуем загрузить очередной параметр
							НазвПрм = ЧтениеXML.ЛокальноеИмя;
						ИначеЕсли ЧтениеXML.ТипУзла = ТипУзлаXML.Текст Тогда
							Если (НазвПрм <> "") И (НастрПрогр.Свойство("Set_" + НазвПрм)) Тогда
								НастрПрогр_SetPrmFromStrVal(НастрПрогр, НазвПрм, ЧтениеXML.Значение);
							КонецЕсли
						ИначеЕсли ЧтениеXML.ТипУзла = ТипУзлаXML.КонецЭлемента Тогда
							НазвПрм = ""
						КонецЕсли
					КонецЕсли
				КонецЕсли
			КонецЦикла;
			// Окончание загрузки
			Если НастрПрогр.ErrMsg = "" Тогда
				НастрПрогр.ChangeInfo = Ложь;  // Нет несохраненных изменений
				Рез = Истина  // Загрузка прошла успешно
			КонецЕсли
		Исключение
			// Ошибка при чтении XML
			НастрПрогр.ErrMsg = "НастрПрогр_LoadSettingsFromXML: " + ИнформацияОбОшибке().Описание;
		КонецПопытки
	Иначе
		// Неверно переданы параметры
		НастрПрогр.ErrMsg = "НастрПрогр_LoadSettingsFromXML: Неверно переданы параметры";
	КонецЕсли;
			
	Возврат Рез
	
КонецФункции

// Сохраняет структуру в XML-документ, пользуясь объектом ЗаписьXML.
//
// Параметры:
//  НастрПрогр - ссылка на объект
//  ЗаписьXML - объект для записи XML-документа
// Возврат
//  Истина, если сохранение прошло удачно и Ложь - в противном случае
//
Функция НастрПрогр_SaveSettingsToXML(НастрПрогр, ЗаписьXML) Экспорт
	
	Рез = Ложь;  // Еще ничего сохранить не успели
	НастрПрогр.ErrMsg = "";
	
	Если ЗаписьXML <> Неопределено Тогда
		Попытка
			// Процесс сохранения
			ЗаписьXML.ЗаписатьОбъявлениеXML();
			ЗаписьXML.ЗаписатьНачалоЭлемента("settings");
			// Выгрузить каждый параметр
			Для Каждого Item Из НастрПрогр Цикл
				Если Найти(Item.Ключ, "Set_") = 1 Тогда
					НазвПрм = Сред(Item.Ключ, 5);
					Если НазвПрм <> "" Тогда
						ЗаписьXML.ЗаписатьНачалоЭлемента(НазвПрм);
						ЗаписьXML.ЗаписатьТекст(Строка(НастрПрогр_GetPrmStrVal(НастрПрогр, НазвПрм)));
						ЗаписьXML.ЗаписатьКонецЭлемента()  // параметр
					КонецЕсли
				КонецЕсли
			КонецЦикла;
			// Завершение формирования XML-документа
			ЗаписьXML.ЗаписатьКонецЭлемента();  // settings
			
			Если НастрПрогр.ErrMsg = "" Тогда
				НастрПрогр.ChangeInfo = Ложь;  // Нет несохраненных изменений
				Рез = Истина  // Сохранение прошло успешно
			КонецЕсли
		Исключение
			// Ошибка при записи XML
			НастрПрогр.ErrMsg = "НастрПрогр_SaveSettingsToXML: " + ИнформацияОбОшибке().Описание;
		КонецПопытки
	Иначе
		// Неверно переданы параметры
		НастрПрогр.ErrMsg = "НастрПрогр_SaveSettingsToXML: Неверно переданы параметры";
	КонецЕсли;
			
	Возврат Рез
	
КонецФункции

// Загружает структуру из XML-документа, размещенного в строке XMLStr.
//
// Параметры:
//  НастрПрогр - ссылка на объект
//  XMLStr - строка с XML-документом
// Возврат
//  Истина, если загрузка прошла удачно и Ложь - в противном случае
//
Функция НастрПрогр_LoadSettingsFromXMLStr(НастрПрогр, XMLStr) Экспорт
	
	Рез = Ложь;  // Еще ничего загрузить не успели
	НастрПрогр.ErrMsg = "";
	
	Если (XMLStr <> Неопределено) И (XMLStr <> "") Тогда
		Попытка
			ЧтениеXML = Новый ЧтениеXML();
			ЧтениеXML.УстановитьСтроку(XMLStr);
			// Выполнить основные операции
			Рез = НастрПрогр_LoadSettingsFromXML(НастрПрогр, ЧтениеXML);
		Исключение
			// Ошибка при чтении XML
			НастрПрогр.ErrMsg = "НастрПрогр_LoadSettingsFromXMLStr: " + ИнформацияОбОшибке().Описание;
		КонецПопытки
	Иначе
		// Неверно переданы параметры
		НастрПрогр.ErrMsg = "НастрПрогр_LoadSettingsFromXMLStr: Неверно переданы параметры";
	КонецЕсли;
			
	Возврат Рез
	
КонецФункции

// Сохраняет структуру в XML-документ, в строку XMLStr.
//
// Параметры:
//  НастрПрогр - ссылка на объект
//  XMLStr - строка, куда помещается XML-документ
// Возврат
//  Истина, если сохранение прошло удачно и Ложь - в противном случае
//
Функция НастрПрогр_SaveSettingsToXMLStr(НастрПрогр, XMLStr) Экспорт
	
	Рез = Ложь;  // Еще ничего сохранить не успели
	НастрПрогр.ErrMsg = "";
	
	Попытка
		ЗаписьXML = Новый ЗаписьXML();
		ЗаписьXML.УстановитьСтроку();
		// Выполнить основные операции
		Рез = НастрПрогр_SaveSettingsToXML(НастрПрогр, ЗаписьXML);
		// Возврат XML-документа в текстовой строке
		Если Рез Тогда
			XMLStr = ЗаписьXML.Закрыть();
		КонецЕсли
	Исключение
		// Ошибка при записи XML
		НастрПрогр.ErrMsg = "НастрПрогр_SaveSettingsToXMLStr: " + ИнформацияОбОшибке().Описание;
	КонецПопытки;
			
	Возврат Рез
	
КонецФункции

// Загружает структуру из XML-файла FName.
//
// Параметры:
//  НастрПрогр - ссылка на объект
//  FName - название файла с XML-документом
// Возврат
//  Истина, если загрузка прошла удачно и Ложь - в противном случае
//
Функция НастрПрогр_LoadSettingsFromFile(НастрПрогр, Знач FName) Экспорт
	
	Рез = Ложь;  // Еще ничего загрузить не успели
	НастрПрогр.ErrMsg = "";
	
	Если (FName <> Неопределено) И (FName <> "") Тогда
		Попытка
			ЧтениеXML = Новый ЧтениеXML();
			ЧтениеXML.ОткрытьФайл(FName);
			// Выполнить основные операции
			Рез = НастрПрогр_LoadSettingsFromXML(НастрПрогр, ЧтениеXML);
		Исключение
			// Ошибка при чтении XML
			НастрПрогр.ErrMsg = "НастрПрогр_LoadSettingsFromFile:" + ИнформацияОбОшибке().Описание;
		КонецПопытки
	Иначе
		// Неверно переданы параметры
		НастрПрогр.ErrMsg = "НастрПрогр_LoadSettingsFromFile: Неверно переданы параметры";
	КонецЕсли;
			
	Возврат Рез
	
КонецФункции

// Сохраняет структуру в XML-документ, в файл FName.
//
// Параметры:
//  НастрПрогр - ссылка на объект
//  FName - название файла, куда помещается XML-документ
// Возврат
//  Истина, если сохранение прошло удачно и Ложь - в противном случае
//
Функция НастрПрогр_SaveSettingsToFile(НастрПрогр, Знач FName) Экспорт
	
	Рез = Ложь;  // Еще ничего сохранить не успели
	НастрПрогр.ErrMsg = "";
	
	Если (FName <> Неопределено) И (FName <> "") Тогда
		Попытка
			ПараметрыЗаписиXML = Новый ПараметрыЗаписиXML("windows-1251",,,, "  ");
			ЗаписьXML = Новый ЗаписьXML();
			ЗаписьXML.ОткрытьФайл(FName, ПараметрыЗаписиXML);
			// Выполнить основные операции
			Рез = НастрПрогр_SaveSettingsToXML(НастрПрогр, ЗаписьXML);
			// Закрытие файла
			ЗаписьXML.Закрыть();
		Исключение
			// Ошибка при записи XML
			НастрПрогр.ErrMsg = "НастрПрогр_SaveSettingsToFile: " + ИнформацияОбОшибке().Описание;
		КонецПопытки
	Иначе
		// Неверно переданы параметры
		НастрПрогр.ErrMsg = "НастрПрогр_SaveSettingsToFile: Неверно переданы параметры";
	КонецЕсли;
			
	Возврат Рез
	
КонецФункции


Естественно, что для получения и установки значений параметров нужно использовать подпрограммы «НастрПрогр_GetPrm» и «НастрПрогр_SetPrm» соответственно. Просто так присваивать значения элементам структуры, имитирующей класс, нельзя.

Это тот функционал набора настроек, который является достаточным на мой взгляд. Можете расширить его какими-либо подпрограммами по собственному желанию.

Использование данного хранилища настроек выглядит следующим образом:
// Процедура - обработчик события "При открытии" формы. Данное событие
// возникает при открытии формы до показа окна пользователю.
//
// Параметры:
//  Нет.
//
Процедура ПриОткрытии()

	// Загрузить настройки программы
	НастрПрогр = НастрПрогр_Конструктор();
	XMLStr = ВосстановитьЗначение("ТестоваяОбработка_НастройкиПрограммы");
	Если XMLStr <> Неопределено Тогда
		НастрПрогр_LoadSettingsFromXMLStr(НастрПрогр, XMLStr)
	КонецЕсли;
	
КонецПроцедуры

// Процедура - обработчик события "При закрытии" формы. Данное событие
// возникает после закрытия формы.
// Освобождение занятых ресурсов.
//
// Параметры:
//  Нет.
//
Процедура ПриЗакрытии()

	// Сохранить настройки программы
	Если НастрПрогр_GetChangeInfo(НастрПрогр) Тогда
		XMLStr = "";
		НастрПрогр_SaveSettingsToXMLStr(НастрПрогр, XMLStr);
		СохранитьЗначение("ТестоваяОбработка_НастройкиПрограммы", XMLStr);
	КонецЕсли;
	НастрПрогр_Деструктор(НастрПрогр);
	
КонецПроцедуры

// Процедура - обработчик события "Нажатие" кнопки КнопкаВыводЗначений.
// Выводит текущие значения набора параметров.
//
// Параметры:
//  Элемент - элемент формы - кнопка
//
Процедура КнопкаВыводЗначенийНабораНажатие(Элемент)

	Сообщить("Параметр1 = " + НастрПрогр_GetPrm(НастрПрогр, "Парам1"));
	Сообщить("Параметр2 = " + НастрПрогр_GetPrm(НастрПрогр, "Парам2"));
	Сообщить("Параметр3 = " + НастрПрогр_GetPrm(НастрПрогр, "Парам3"));
	Сообщить("Параметр4 = " + НастрПрогр_GetPrm(НастрПрогр, "Парам4"));
	Сообщить("Параметр5 = " + НастрПрогр_GetPrm(НастрПрогр, "Парам5"));
	
КонецПроцедуры

Теперь разберем код диалогового окна для редактирования набора настроек. Для нашего демонстрационного набора параметров оно будет выглядеть примерно так:



Разместим на форме соответствующие элементы управления для отображения и редактирования параметров. Создадим у формы реквизиты – для каждого параметра отдельный, и привяжем к ним элементы управления. Обмен данными уже будем вести между хранилищем настроек (объектом класса НастрПрогр) и этими реквизитами.
Исходный код модуля этой формы будет следующим:
Код модуля ФормаНастройкиПараметров
////////////////////////////////////////////////////////////////////////////////
// ДИАЛОГ НАСТРОЙКИ ПАРАМЕТРОВ ПРОГРАММЫ

Перем НастрПрогр;   // Объект с настройками программы


////////////////////////////////////////////////////////////////////////////////
// ОБРАБОТЧИКИ СОБЫТИЙ ФОРМЫ

// Процедура - обработчик события "При открытии" формы. Данное событие
// возникает при открытии формы до показа окна пользователю.
//
// Параметры:
//  Нет.
//
Процедура ПриОткрытии()

	// Перевести фокус на начальное поле ввода
	ТекущийЭлемент = ЭлементыФормы.ПолеВводаПараметр1
	
КонецПроцедуры

// Процедура - обработчик события "Нажатие" кнопки КнопкаOK.
// Попытка закрытия диалога с применением настроек.
//
// Параметры:
//  Элемент - кнопка
//
Процедура ОсновныеДействияФормыКнопкаОК(Кнопка)
	
	Если CheckInput() Тогда
		ЭтаФорма.Закрыть(КодВозвратаДиалога.ОК)
	КонецЕсли
	
КонецПроцедуры


////////////////////////////////////////////////////////////////////////////////
// ВСПОМОГАТЕЛЬНЫЕ ПОДПРОГРАММЫ

// Считывает параметры из полей ввода формы и проверяет параметры на корректность.
//
// Параметры:
//  Нет
// Возврат:
//  Истина, если параметры заданы корректно и Ложь - в противном случае
//
Функция CheckInput()
	
	Рез = Ложь;
	ErrMsg = "";
	
	// Здесь можно выполнить какие-то проверки
	// ********************************
	
	// Анализируем результат проверки полей ввода
	Если ErrMsg = "" Тогда
		// Все параметры корректны
		ReadSettingsFromInterf();  // Считать из интерфейса сделанные настройки
		Рез = Истина
	Иначе
		Предупреждение(ErrMsg)
	КонецЕсли;

	Возврат Рез
	
КонецФункции

// Загружает все настройки в интерфейс.
//
// Параметры:
//  Нет
//
Процедура LoadSettingsToInterf()
	
	Если НастрПрогр <> Неопределено Тогда
		// Установить значения
		Парам1 = НастрПрогр_GetPrm(НастрПрогр, "Парам1");
		Парам2 = НастрПрогр_GetPrm(НастрПрогр, "Парам2");
		Парам3 = НастрПрогр_GetPrm(НастрПрогр, "Парам3");
		Парам4 = НастрПрогр_GetPrm(НастрПрогр, "Парам4");
		Парам5 = НастрПрогр_GetPrm(НастрПрогр, "Парам5");
	КонецЕсли
	
КонецПроцедуры

// Считать все настройки из интерфейса.
//
// Параметры:
//  Нет
//
Процедура ReadSettingsFromInterf()
	
	Если НастрПрогр <> Неопределено Тогда
		// Считать значения
		НастрПрогр_SetPrm(НастрПрогр, "Парам1", Парам1);
		НастрПрогр_SetPrm(НастрПрогр, "Парам2", Парам2);
		Если ЗначениеЗаполнено(Парам3) Тогда
			НастрПрогр_SetPrm(НастрПрогр, "Парам3", Парам3)
		Иначе
			НастрПрогр_SetPrm(НастрПрогр, "Парам3", Неопределено)
		КонецЕсли;
		НастрПрогр_SetPrm(НастрПрогр, "Парам4", Парам4);
		НастрПрогр_SetPrm(НастрПрогр, "Парам5", Парам5);
	КонецЕсли
	
КонецПроцедуры


////////////////////////////////////////////////////////////////////////////////
// ПОДПРОГРАММЫ ВНЕШНЕГО ИНТЕРФЕЙСА

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


А вот так используется это диалоговое окно (из окна главной формы):
// Процедура - обработчик события "Нажатие" кнопки КнопкаДиалогНастроек.
// Вызывает диалог установки основных настроек обработки.
//
// Параметры:
//  Элемент - элемент формы - кнопка
//
Процедура КнопкаДиалогНастроекНажатие(Элемент)
	
	// Создаем временный набор настроек
	ВремНастрПрогр = НастрПрогр_Конструктор();
	НастрПрогр_Assign(ВремНастрПрогр, НастрПрогр);
	НастрПрогр_SetChangeInfo(ВремНастрПрогр, Ложь);
	// Вызываем диалог ввода настроек
	ФормаНастройкиПараметров = ЭтотОбъект.ПолучитьФорму("ФормаНастройкиПараметров", ЭтаФорма);
	Если ФормаНастройкиПараметров.SetMainSettingsDlg(ВремНастрПрогр) Тогда
		// Параметры изменены
		Если НЕ НастрПрогр_IsEqual(НастрПрогр, ВремНастрПрогр) Тогда
			// Сохранить настройки в основной набор
			НастрПрогр_Assign(НастрПрогр, ВремНастрПрогр);
		КонецЕсли
	КонецЕсли;
	НастрПрогр_Деструктор(ВремНастрПрогр)
	
КонецПроцедуры

Вот так все это делается. Ничего сложного нет. Но лично мне нравится четкий, организованный подход. Ну и переносимость опять же. Ведь для превращения этого хранилища настроек в любое другое, достаточно совершенно не задумываясь, механически переписать следующие подпрограммы:
Функция НастрПрогр_СоздатьОбъект()
Процедура НастрПрогр_SetDefAttr(НастрПрогр)
Функция НастрПрогр_GetPrmStrVal(НастрПрогр, PrmName) 
Процедура НастрПрогр_SetPrmFromStrVal(НастрПрогр, PrmName, StrPrmVal)

Скачать исходные тексты рассмотренных программ (обработка для 1С 8.2) можно здесь.

На этом все. Всем удачи. До встречи.

Комментарии (2)


  1. JetMaster
    05.12.2015 14:19
    +9

    Функция НастрПрогр_СоздатьОбъект()
    Процедура НастрПрогр_SetDefAttr(НастрПрогр)
    Функция НастрПрогр_GetPrmStrVal(НастрПрогр, PrmName) 
    Процедура НастрПрогр_SetPrmFromStrVal(НастрПрогр, PrmName, StrPrmVal)
    


    image


  1. Melex
    05.12.2015 16:43
    +3

    Хорошо, что появляются такого рода статьи, но лучше — если на профильном сайте, там вам хоть подскажут как сделать все правильней.
    Ну например — там можно почитать про то, что такое сериализация и десериализация, и убрать половину вашего кода. Ну и многое всякое другое. Красиво оформленный код с комментариями из серии Читаем xml файл, и использование Попытки там, где надо получать свойство структуры…
    Это даже не смешно, увы :(