Информационный поток
Задания вакансии материалы разработки сообщения форума
Рубрики статей и материалов
Яндекс-директ

Встраиваем Silverlight-приложение в любую форму 1С: Предприятие. Часть 2.

  • Добавить свою публикацию
  • для этого требуется регистрация

Ссылка на первую часть статьи

По итогам прошлой статьи у нас есть форма 1С (внешней обработки) с полем HTML документа и Silverlight-приложение, работающее в нем самостоятельно. Разумеется, нам хотелось бы каким-то образом воздействовать на него и обмениваться данными, по крайней мере, в одностороннем порядке, если мы хотим средствами Silverlight визуализировать какую-либо информацию.
Изучая HTML документ, созданный отладчиком Visual Studio, мы обратили внимание на вставку JavaScript когда, который обрабатывал ошибки запуска Silverlight. Более того, технология Silverlight предполагает, что приложение будет вставлено в какую-то область страницы и будет взаимодействовать с ней. Стало быть, Silverlight-приложение умеет общаться с родителем - страницей, на которой оно расположено. Значит, нам следует изучить возможности 1С по взаимодействию с полем HTML. Получается следующая схема:

Изображение

Взаимодействие 1С и JavaScript

Инициатор - 1С

Начнем с первой части схемы. Допустим, будем выводить средствами JavaScript произвольную строку, вводимую пользователем в нашей форме. Создадим новый реквизит типа Строка неограниченной длины и добавим на форму соответствующее поле ввода. Для поля создадим обработчик события "ПриИзменении", в котором пока ничего писать не будем, а откроем макет HTML страницы. Здесь внутрь тега, отвечающего за описание скриптов () поместим код нашей простой функции, выводящей переданный ей параметр.

Изображение

Мы немного преобразуем полученную строку, отобразим на экране и возвратим. Стандартная функция alert() работает аналогично Сообщить() в 1С. Вообще говоря, параметр не обязательно может быть строковым, как и в 1С, в JavaScript мягкая типизация, alert() попытается преобразовать значение в строку. Теперь вызовем эту функцию из нашего обработчика, есть два способа, запишем их оба:

 

 

&НаКлиенте
Процедура СообщениеПриИзменении(Элемент)
	Сообщить(Элементы.ДокументHTML.Документ.parentWindow.ShowMessage(Сообщение));
	Сообщить(Элементы.ДокументHTML.Документ.parentWindow.eval("ShowMessage(""" + Сообщение + """)"));
КонецПроцедуры

 

Таким образом, мы продублируем вывод строки еще и в среде 1С, чтобы убедиться, что возврат значений работает верно. Запустим обработку, введем текст в поле и убедимся, что оно выведется два раза в виде отдельных окошек сообщений и в виде сообщений 1С.

Изображение

В чем же разница в вызовах? Увы, достоверной информации по этому поводу найти трудно, но, очевидно, что второй вариант более ограничен в параметрах - они могут быть лишь строковыми (хотя число передать можно, но придется затем приводить тип в JS). В тоже время, если вы попытаетесь возвратить массив, созданный в JS, то "eval" приведет его к виду, понятному для 1С, а обычный вызов нет. Что же делать, если нам нужно передать что-то не строковое, а получить массив? Передавать его как один из параметров! Добавим еще одну JS функцию:

Изображение

Она принимает два параметра - входящий массив и тот, в который мы запишем результат. Результатом будет простое добавление "JS: " перед каждым элементом массива (предположим, что элементы строковые). Да, JS спокойно работает с массивами 1С, позволяя оперировать знакомыми методами "Добавить()", "Количество()" и т.д. Увы, не будет работать индексация, поэтому пользуемся функцией "Получить()". В 1С добавим на форму кнопку, привяжем к команде, содержащей следующий код:

 

 

&НаКлиенте
Процедура test(Команда)
	мсJS = Новый Массив;
	мсOut = Новый Массив;
	мсJS.Добавить("First element");
	мсJS.Добавить("Second element");
	Элементы.ДокументHTML.Документ.parentWindow.ChangeArray(мсJS, мсOut);
	Для Каждого элOut Из мсOut Цикл
		Сообщить(элOut);
	КонецЦикла;
КонецПроцедуры

 

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

Инициатор - JavaScript

Итак, передавать и получать значения мы умеем, но пока у нас инициатором этого обмена был лишь 1С. Хотелось бы и наоборот. Разумеется, просто вызывать функции 1С и получать от данные мы в JS не можем, хотя бы из соображений безопасности (не забываем, что мы имеем дело с кодом, который может быть расположен на любой странице в интернете). Но оповестить 1С о своих действиях JS может.
Те, кто работал с полем HTML документа в обычных формах, видел, что у него обширный список обработчиков событий, фактически, можно было отловить любое событие HTML, от onclick до onhelp. Что же видим в форме управляемой? "ПриИзменении", "ДокументСформирован" и "Нажатие"... Негусто, странное решение 1С, но что поделать. Будем использовать "Нажатие". Давайте оповестим 1С о том, что формирование массива нашей функцией закончено. Вот здесь нам понадобится буфер. Итак, заведем глобальную переменную и в нашу функцию ChangeArray добавим код:

Изображение

Теперь создадим обработчик события HTML поля "Нажатие" и в нем выведем содержимое буфера:

 

 

&НаКлиенте
Процедура ДокументHTMLПриНажатии(Элемент, ДанныеСобытия, СтандартнаяОбработка)
	Если Элементы.ДокументHTML.Документ.parentWindow.outBuffer Неопределено Тогда
		Сообщить(Элементы.ДокументHTML.Документ.parentWindow.outBuffer);
	КонецЕсли;
КонецПроцедуры

 

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

ИзображениеВ нашем случае "Нажатие" удобно тем, что, поскольку, всю рабочую область поля у нас занимает Silverlight-приложение, вызвать данное событие можно только через JS, остальные нажатия перехватит Silverlight. Функция fireEvent() может иметь два параметра, второй содержит EventObject, информация в котором могла бы нам помочь узнать, кто вызвал событие. Доступен он будет в параметре обработчика "ДанныеСобытия".

Таким образом, мы научили сообщаться 1C и JS в поле HTML. Это важный момент, поскольку уже средства JS позволяют значительно расширить функционал 1С. JS (особенно вкупе с SVG) замечательно управляется с графикой, имеет множество библиотек. В чем же преимущества Silverlight? Во-первых, в удобстве. Здесь и отличный отладчик Visual Studio, и возможность программирования на языках .NET, и удобная разметка с помощью XAML. Во-вторых, скомпилированный код Silverlight работает быстрее (хотя здесь нужно учитывать, что посредником все равно выступает JS). Выбор конкретного средства зависит от разработчика.

Взаимодействие Silverlight и JavaScript

Отступление - прямой вызов из 1С

Теперь пора приступить ко второй части нашей связки, мы будем работать с JS и Silverlight. Хотя сначала мы рассмотрим способ вызова функций Silverlight из 1С напрямую. Итак, первое, что нам нужно сделать - как-то идентифицировать наше приложение на странице, для чего откроем наш макет и найдем объявление приложения (мы разбирали его параметры) и присвоим ему идентификатор silverlightControl:

Изображение

Он может быть любым, но по этому названию мы будем искать приложение на странице. Теперь снова будем работать в Visual Studio, отрываем наш проект. Изначально объекты и методы приложения Silverlight закрыты от посторонних и вызвать их нельзя, исправим это, для чего сделаем следующее:

  1. Подключим библиотеку "System.Windows.Browser", это делается с помощью ключевого слова "using", библиотеки подключаются в начале когда модуля.
  2. Класс нашего приложения установим как "Scriptable", для этого перед его объявлением добавим "[ScriptableType()]".
  3. После процедуры инициализации зарегистрируем приложение, добавив HtmlPage.RegisterScriptableObject("SilvApp", this), первый параметр функции опять-таки нужен, чтобы мы по нему могли потом обращаться, можно выбрать другое.
  4. Добавим новый метод, который, как и нажатие кнопки, будет в текстовое поле выводить "Hello World!" и возвращать строку с сообщением об успешно выполненной команде. Метод следует объявить как "[ScriptableMember()]".

На скриншоте видны все действия:

Изображение

Компилируем (F6), внешне ничего не изменилось, так что запуск нас не интересует. Не забываем, что теперь нужно загрузить новый xap-файл в макет нашей обработки. Теперь в 1С добавим еще одну кнопку, команда которой будет содержать следующий код:

 

&НаКлиенте
Процедура test2(Команда)
	SilvElement = Элементы.ДокументHTML.Документ.getElementById("silverlightControl");
	Если SilvElement Неопределено Тогда
		Сообщить(SilvElement.content.SilvApp.SayHello());
	КонецЕсли;
КонецПроцедуры

 

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

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

Вызовы из Silverlight и JavaScript

Вызов функции Silverlight из JS происходит аналогично рассмотренному только что, методы тоже должны быть "Scriptable", а приложение иметь зарегистрированное имя. Код вызова:

 

 

var SilvElement = document.getElementById("silverlightControl");
if (SilvElement != null) {
	SilvElement.content.SilvApp.SayHello();
}

 

Аналогично обращаемся к методу документа, чтобы найти объект, а затем по имени приложения вызываем функцию. В данном случае можно передавать параметры, ошибок не будет. Думаю, здесь уже нет необходимости приводить примеры, можете сами доработать функцию SayHello, чтобы она устанавливала переданное пользователем значение и возвращала какое-то оповещение, а затем из 1С вызвать код JS, с переданным ему сообщением, который обратится к данной функции.
Теперь о вызове JavaScript кода из Silverlight. По щелчку мыши на кнопку в Silverlight будем вызывать нашу функцию ShowMessage из JS. Все очень просто:

 

 

private void Button_Click_1(object sender, RoutedEventArgs e)
{
	TextBlock1.Text = "Hello World!";
	HtmlPage.Window.Invoke("ShowMessage", "Оповещение от Silverlight!");
}

 

Метод Invoke первым параметром принимает имя функции, а последующими - её аргументы.

Заключительный пример

И, напоследок, еще один пример. Попробуем передать файл-картинку, выбираемый в 1С, а в Silverlight установим его в качестве фона. На форме добавим третью кнопку, укажем ей новую команду, которая будет вызывать диалог открытия файла.

 

 

&НаКлиенте
Процедура ОткрытьИзобр(Команда)
	ДиалогОткрытияФайла = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие);
	ДиалогОткрытияФайла.Фильтр = "Изображения (*.jpg)|*.jpg";
	ДиалогОткрытияФайла.Заголовок = "Выберите файлы";
	Если ДиалогОткрытияФайла.Выбрать() Тогда
		ДанныеФайла = Новый ДвоичныеДанные(ДиалогОткрытияФайла.ВыбранныеФайлы[0]);
		Сообщить(Элементы.ДокументHTML.Документ.parentWindow.SendImg(Base64Строка(ДанныеФайла)));
	КонецЕсли;
КонецПроцедуры

 

Сделать из файла пригодный для передачи параметр помогает функция "Base64Строка", которая позволяет передать двоичные данные в виде строки. Код вызываемой функции "SendImg" на JS:

function SendImg (base64str) {
var SilvElement = document.getElementById("silverlightControl");
if (SilvElement != null) {
ans = SilvElement.content.SilvApp.SetImg(base64str);
}
return ans; 
}

 

Здесь мы просто передаем строку "дальше" - в Silverlight-приложение и получаем ответ, который в 1С выведет функция "Сообщить". И, наконец, код функции "SetImg" в Silverlight:

//добавления в раздел "using"
using System.Windows.Media.Imaging;
using System.IO;
//Сам метод
[ScriptableMember()]
public String SetImg(String base64str)
{
byte[] buffer = Convert.FromBase64String(base64str);
MemoryStream ms = new MemoryStream(buffer, 0, buffer.Length);
BitmapImage image = new BitmapImage();
image.SetSource(ms);
ImageBrush imgBrush = new ImageBrush();
imgBrush.ImageSource = image;
LayoutRoot.Background = imgBrush;
HtmlPage.Window.Invoke("ShowMessage", "Изображение установлено");
return "Оповещение 1С";
}

 

С помощью стандартного метода Silverlight конвертируем строку в массив байт, сохраняем в MemoryStream и устанавливаем в качестве Source у созданного BitmapImage. Затем создаем кисть с иточником в виде нашего изображения и устанавливаем её свойству Background. В JS вызываем функцию-оповещение с сообщением об успешной установке изображения, а возвращаемый параметр "уйдет", опять-таки через JS, в 1С. Собственно, всё!

Изображение

В заключение

Надеюсь, что 1С и дальше будет развивать компоненту WebBrowser, что когда-нибудь она не будет жестко привязана к IE и мы сможем ожидать, например, поддержку HTML5. Это позволит расширить не только возможности локального приложения, но и полностью позволит взаимодействовать с различными API в интернете (а об этом еще надеюсь поговорить). В любом случае, теперь вы будете к этому подготовлены. Разумеется, некоторые моменты в статье были опущены, например, передача сложных объектных данных, вроде элементов справочников - это достигается с помощью xml-сериализации и не имеет прямого отношения к взаимодействию с JS или Silverlight, т.к. касается общих (стандартных) механизмов передачи.

 
0
Читайте также
Установка PostgreSQL 9.0.3-3.1C на Windows Server 2008 x64
"Windows Server 2008 x64 Как установить PostgreSQL 9.0.3-3.1C"
Пишем в 1с для Android
Возможность работыв 1с на телефонах с Андроид
Разработки
Просмотрщик CD файлов
Просмотрщик файлов с расширением .cd
МОЗГОДЕР - универсальное решение для пользователей
Решение практически любого вопроса и проблемы в 1С
Проверка и групповая корректировка адресов в ЗУП на соответствие КЛАДР
Проверка правильного заполнения адресов 1С ЗиУП 8
Еще от автора
≡ к списку статей