Есть реестр раздела, есть окно редактирования записей реестра, на этом окне редактирования две закладки, на одной из закладок WindowContainer - свойство Window = ОкноНаследник-wnd_BaseGridArea, в этом окне расположен грид, в который нужно добавлять данные, редактировать и тд и тп...
Как проинициализировать всю эту цепочку:
Кликнул на реестре - открылось окно редактрования, в нем на одной закладке отображаются данные текущей записи реестра, на другой закладке в гриде отображаются данные, которые лежат в другой таблице и ссылаются на текущую запись реестра, под этим гридом нажимаю кнопку (добавить, изменить, удалить) - открывается окно редактирования текущей записи грида.
Нравится
Добрый день.
Правильно я понимаю, что у Вас в окне редактирования две страницы (Pages), на одной из которых основные данные, а на другой - реестр с данными из другой таблицы? Можно сделать так: написать функцию инициализации и обновления реестра по аналогии с тем, как реализованы подобные функции для деталей в разделе (примеры можно посмотреть в любом из скриптов, название которого содержит Workspace; функции обычно называются Initialize...Detail и Refresh...Detail соответственно). Но при реализации необходимо учесть, что в примерах родительским окном является окно раздела, а в Вашем случае это будет окно редактирования. По этой причине не получится использовать базовую функцию RefreshCommonDetail (скрипт scr_WorkspaceUtils), но можно создать по аналогии свою функцию.
Когда функции инициализации и обновления готовы, можно определить обработчик события OnChangeActivePage для объекта Pages. В этом обработчике проверять название активной страницы, и если это страница, содержащая реестр, вызывать функцию обновления для окна реестра.
Да, Вы правильно меня поняли. Я уже добился обновления этого реестра на одной из Page, но при этом:
1. его кнопка "добавить" почему то неактивна;
2. окно редактирования этого реестра не позволяет редактировать данные, даже не отображает их, а при попытке нажать на кнопку "ок" выдает ошибку о неоткрытом датасете;
3. нажатие кнопки "удалить" вообще не приводит к каким либо последствиям.
То что я наворотил выглядит так:
событие OnPrepare окна карточки редактирования (это в ней две Page, на одной из которых расположен грид (реестр)):
[javascript]
function wnd_BaseDBEditOnPrepare(Window) {
scr_BaseDBEdit.wnd_BaseDBEditOnPrepare(Window);
SetAttribute(wcExpence.Window,'ParentItemFieldName', 'S_ID');
SetAttribute(wcExpence.Window,'EditWindowUSI', 'wnd_SiteExpEdit');
SetAttribute(wcExpence.Window,'DatasetUSI', 'sq_CashflowExp');
wcExpence.Window.Prepare();
if (Pages.ActivePage.Name == 'Page1'){
PagesOnChangedActivePage(Pages)
}
}
[/javascript]
событие OnChangedActivePage объекта Pages:
[javascript]
function PagesOnChangedActivePage(Pages) {
var DatasetSite = dlData.Dataset;
var S_ID = DatasetSite.Values('ID');
if (Pages.ActivePage.Name == 'Page1'){
var DatasetCashflow = wcExpence.Window.ComponentsByName('dlData').Dataset;
DatasetCashflow.Close();
ApplyDatasetFilter(DatasetCashflow, 'S_ID', S_ID, true);
DatasetCashflow.Open();
}
}
[/javascript]
Сразу возникло несколько замечаний:
1) Почему в атрибут DatasetUSI передаётся запрос, а не датасет?
2) Я бы использовал событие PagesOnChangeActivePage, а не PagesOnChangedActivePage. Первое событие автоматически срабатывает при изменении активной страницы. В связи с этим:
3) Не совсем понимаю, зачем в wnd_BaseDBEditOnPrepare вызывать
[javascript]
if (Pages.ActivePage.Name == 'Page1'){
PagesOnChangedActivePage(Pages)
}
[/javascript]
4) Кнопка "Добавить" может быть неактивна из-за того, что в окне реестра не определён атрибут ParentItemID. Попробуйте его передавать при обновлении дочернего реестра.
Определил атрибут ParentItemID:
[javascript]
SetAttribute(wcExpence.Window,'ParentItemID','SiteID');
[/javascript]
кнопка "добавить" стала доступна. Но окно редактирования всё равно не инициализируется и датасет этого окна не открывается, а он, если я правлиьно понимаю, должен не просто открываться, а открываться в определенном режиме в зависимости от нажатой кнопки.
"SSV" написал:4) А можно подробнее?
С учётом Вашего кода, думаю, получится где-то так:
[javascript]
var DatasetSite = dlData.Dataset;
var S_ID = DatasetSite.Values('ID');
if (Pages.ActivePage.Name == 'Page1'){
var DatasetCashflow = wcExpence.Window.ComponentsByName('dlData').Dataset;
SetAttribute(wcExpence.Window, 'ParentItemID', S_ID);
RefreshDetailData(DatasetSite, 'ID', DatasetCashflow, 'S_ID');
}
[/javascript]
Это при условии, что в запросе дочернего реестра создан параметр с названием S_ID и фильтр с кодом S_ID сравнения соответствующей колонки с этим параметром. Попробуйте это вместо кода
[javascript]
DatasetCashflow.Close();
ApplyDatasetFilter(DatasetCashflow, 'S_ID', S_ID, true);
DatasetCashflow.Open();
[/javascript]
Попробуйте всё-таки выполнять обновление реестра не на OnPrepare окна редактирования, а в обработчике события OnChangeActivePage объекта Pages.
Всё сделал, как Вы написали, но окно редактирования этого дочернего реестра всё равно не работает
([javascript]
SetAttribute(wcExpence.Window,'EditWindowUSI', 'wnd_SiteExpEdit');
[/javascript]).
Оно открывается, но в поля редактирования ничего нельзя впечатать и ни одно поле не инициализируется текущими значениями.
Это реализовано в функционале базовых окон реестра и редактирования: во-первых, события по нажатию кнопок "Добавить" и "Изменить" обрабатываются по-разному. Окну редактирования передаётся атрибут RecordID, и если он содержит пустое значение (первый случай), датасет окна устанавливается в режим добавления записи (Dataset.Append()). Если же этот атрибут не пустой, датасет устанавливается в режим редактирования (Dataset.Edit()).
Установка атрибутов перед вызовом окна редактирования по факту осуществляется с помощью функции AddRequiredValuesToDictionary (во всех случаях), но она в разных случаях получает разные атрибуты. Посмотрите её текст в скрипте scr_BaseGridAreaUtils, а также тексты функций, которые её вызывают: GetAddDataAttributes, GetCopyDataAttributes, GetEditDataAttributes и т.д.
Можете выложить все сервисы, которые касаются окна редактирования и его компонент? Попытаюсь разобраться, почему не работает.
Хм, а может я не всё корректно тут изложил. Дело в том, что в окне редактирования, на котором лежит объект Pages, есть еще один даталинк, который и содержит датасет с данными из дочернего реестра. Даталинк с тем же датасетом есть в окне редактирования дочернего реестра. Может здесь проблема? Может эти датасеты нужно как то увязать?
Да, в контекстном меню дерева сервисов есть возможность сохранить сервис в файл.
Что касается второго даталинка, Вы как-то с ним работаете в скрипте основного окна? Если нет, то не думаю, чтобы он как-то повлиял.
Есть несколько вопросов.
Я имел в виду все сервисы, касающиеся окна редактирования, включая таблицы, окна, скрипты, запросы, датасеты.
Кроме того, архив полностью не распаковывается, извлекаются только два датасета и окно. Можете выложить их повторно?
Также прошу уточнить версию Terrasoft. Мне удалось определить только, что она ниже 3.1.0.
И последнее: при загрузке wnd_SiteExpenceEdit у меня пропадает окно wnd_BaseDBEdit. Значит ли это, что Вы получили это окно путём редактирования базового окна?
Заранее благодарен за помощь.
Мне кажется, для корректной работы (если в остальном окно работает нормально) должно быть достаточно такого текста в обработчике PagesOnChangedActivePage:
[javascript]
function PagesOnChangedActivePage(Pages) {
if (Pages.ActivePage.Name == 'Page1'){
var DatasetCashflow = wcExpence.Window.ComponentsByName('dlData').Dataset;
var SiteID = dlData.Dataset.Values('ID');
SetAttribute(wcExpence.Window,'ParentItemFieldName', 'SiteID');
SetAttribute(wcExpence.Window,'EditWindowUSI', 'wnd_SiteExpenceEdit');
SetAttribute(wcExpence.Window, 'ParentItemID', SiteID);
RefreshDetailData(dlData.Dataset, 'ID', DatasetCashflow, 'SiteID');
}
}
[/javascript]
По крайней мере, с таким кодом у меня нормально добавлялись новые записи в дочерний реестр.
Что касается остальных функций, то для корректного редактирования Вам необходимо создать фильтр с кодом ID (и соответствующий параметр) в запросе sq_CashflowExp, а для удаления - указать в качестве ключевого поля поле ID в датасете ds_CashflowExp.
Записи начали удаляться.
А вот остальные функции так и не заработали - не редактируются поля Сумма и Описание, только дату можно выбрать. Кроме этого заметил еще вот что - при повторном вызове окна wnd_SiteExpenceEdit в одном сеансе работы программы, у него пропадает заголовок и названия полей (Дата, Сумма, Описание). Получается, что датасет в даталинке этого окна вообще куда то пропадает?
Попытался нажимать кнопку ОК в окне wnd_SiteExpenceEdit - в скрипте scr_BaseDBEditUtils в функции CheckRequiredDataControl, на строке [javascript]
var Condition = !IsEmptyValue(DataField.Value) && (DataField.Value != 0);
[/javascript]
выпадает ошибка о том, что источник данных ds_CashflowExp не открыт. При повторном вызове этого окна и попытке нажать ОК выпадает ошибка о том, что датасет равен NULL уже на строке
[javascript]
var DataField = DatasetLink.Dataset.DataFields(Control.DataFieldName);
[/javascript]
в той же самой функции. Как такое может быть? И почему датасет может не открываться?
После добавления в обработчик события wnd_BaseDBEditOnPrepare окна wnd_SiteExpenceEdit строки
[javascript]
scr_BaseDBEdit.wnd_BaseDBEditOnPrepare(Window);
[/javascript]
всё заработало.
Олег, спасибо за помощь.
Но всё таки осталась неуверенность - у меня пока не сложился в голове алгоритм последовательности действий в таких ситуациях. По большому счету он как раз меня больше всего интересовал. Моей целью было не получить готовое решение, а получить информацию по правильной последовательности и обязательности шагов.
Видимо, у меня всё работало, потому что я не создавал для wnd_SiteExpenceEdit своего скрипта, а в архиве его не было. В этом случае используется базовый скрипт.
По поводу инициализации. В основном инициализация окна извне (из другого окна, по какому-либо событию) заключается в передаче окну необходимых атрибутов и вызова его метода Prepare (во время обработки которого завершается инициализация). Список атрибутов может отличаться для разных окон, в зависимости от их предназначения и дальнейшей функциональности. Например, для реестра детали обязательно нужно указать EditWindowUSI - USI окна редактирования, ParentItemFieldName - название родительского поля, ParentItemID - ID родительского элемента. Иногда необходимо скрыть фрейм кнопок реестра - за это отвечает атрибут HideButtonsFrame. Если в окне реестра явно не указан датасет, необходимо заполнить атрибут DatasetUSI. И так далее. Например:
[javascript]
function InitializeCommunicationsDetail() {
AccountsWorkspace.CommunicationsWindow = wndCommunicationsDetail.Window;
var DetailWindow = AccountsWorkspace.CommunicationsWindow;
SetAttribute(DetailWindow, 'DatasetUSI', 'ds_AccountCommunication');
SetAttribute(DetailWindow, 'ParentItemFieldName', 'AccountID');
SetAttribute(DetailWindow, 'EditWindowUSI', 'wnd_CommunicationEdit');
SetAttribute(DetailWindow, 'WorkspaceDataset', BaseWorkspace.GridDataset);
SetAttribute(DetailWindow, 'ParentItemID',
BaseWorkspace.GridDataset.ValAsStr('ID'));
DetailWindow.Prepare();
AccountsWorkspace.CommunicationsDataset =
DetailWindow.ComponentsByName('dlData').Dataset;
}
[/javascript]
Если необходимо, окна деталей и их датасеты можно запомнить в глобальные переменные скрипта, как в примере выше.
Некоторые атрибуты достаточно передать один раз (в процессе работы с окном они не меняются), но есть и такие (например, ParentItemID), которые нужно обновлять гораздо чаще. Поэтому в таких случаях создают отдельную функцию обновления окна, которая включает в себя функцию инициализации, если окно ещё не проинициализировано. Также эта функция присваивает атрибутам новые значения и обновляет датасет окна. Например:
[javascript]
function RefreshOpportunityDetail() {
if (AccountsWorkspace.InitializeOpportunityFlag != true) {
InitializeOpportunityDetail();
AccountsWorkspace.InitializeOpportunityFlag = true;
}
var AccountID = BaseWorkspace.GridDataset.ValAsGUID('ID');
if (AccountID == AccountsWorkspace.OpportunityOldAccountID) {
return;
} else {
AccountsWorkspace.OpportunityOldAccountID = AccountID;
}
SetAttribute(AccountsWorkspace.OpportunityWindow, 'ParentItemID',
AccountID);
RefreshDetailData(BaseWorkspace.GridDataset, 'ID',
AccountsWorkspace.OpportunityDataset, 'CustomerID');
}
[/javascript]
В принципе, для обновления окна детали в большинстве случаев достаточно тех действий, которые выполняет функция RefreshCommonDetail из скрипта scr_WorkspaceUtils.
Пример вызова окна редактирования:
[javascript]
var EditWindowUSI = 'wnd_ContactEdit';
var Attributes = GetNewDictionary();
var AccountID = BaseWorkspace.GridDataset.ValAsGUID('ID');
Attributes.Add('RecordID', GUID_NULL);
Attributes.Add('NotifyObject', Self);
var DefaultValues = GetNewDictionary();
DefaultValues.Add('AccountID', AccountID);
DefaultValues.Add('OwnerID',
Connector.CurrentUser.ContactID);
ShowEditWindowEx(EditWindowUSI, Attributes, DefaultValues);
[/javascript]
Всё происходит примерно так же: устанавливаем значения атрибутов, значений по умолчанию (которые на самом деле можно записать в атрибут с кодом DefaultValues) и вызываем окно. Рекомендую подробнее ознакомиться с кодом функции ShowEditWindowEx, некоторые её конструкции полезно использовать при написании своих функций.
Надеюсь, это описание будет Вам полезно. Примеры кода взяты из скрипта scr_AccountWorkspace.