Есть реестр раздела, есть окно редактирования записей реестра, на этом окне редактирования две закладки, на одной из закладок WindowContainer - свойство Window = ОкноНаследник-wnd_BaseGridArea, в этом окне расположен грид, в который нужно добавлять данные, редактировать и тд и тп...
Как проинициализировать всю эту цепочку:
Кликнул на реестре - открылось окно редактрования, в нем на одной закладке отображаются данные текущей записи реестра, на другой закладке в гриде отображаются данные, которые лежат в другой таблице и ссылаются на текущую запись реестра, под этим гридом нажимаю кнопку (добавить, изменить, удалить) - открывается окно редактирования текущей записи грида.
Нравится
Добрый день.
Правильно я понимаю, что у Вас в окне редактирования две страницы (Pages), на одной из которых основные данные, а на другой - реестр с данными из другой таблицы? Можно сделать так: написать функцию инициализации и обновления реестра по аналогии с тем, как реализованы подобные функции для деталей в разделе (примеры можно посмотреть в любом из скриптов, название которого содержит Workspace; функции обычно называются Initialize...Detail и Refresh...Detail соответственно). Но при реализации необходимо учесть, что в примерах родительским окном является окно раздела, а в Вашем случае это будет окно редактирования. По этой причине не получится использовать базовую функцию RefreshCommonDetail (скрипт scr_WorkspaceUtils), но можно создать по аналогии свою функцию.
Когда функции инициализации и обновления готовы, можно определить обработчик события OnChangeActivePage для объекта Pages. В этом обработчике проверять название активной страницы, и если это страница, содержащая реестр, вызывать функцию обновления для окна реестра.
Да, Вы правильно меня поняли. Я уже добился обновления этого реестра на одной из Page, но при этом:
1. его кнопка "добавить" почему то неактивна;
2. окно редактирования этого реестра не позволяет редактировать данные, даже не отображает их, а при попытке нажать на кнопку "ок" выдает ошибку о неоткрытом датасете;
3. нажатие кнопки "удалить" вообще не приводит к каким либо последствиям.
То что я наворотил выглядит так:
событие OnPrepare окна карточки редактирования (это в ней две Page, на одной из которых расположен грид (реестр)):
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) } }
событие OnChangedActivePage объекта Pages:
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(); } }
Сразу возникло несколько замечаний:
1) Почему в атрибут DatasetUSI передаётся запрос, а не датасет?
2) Я бы использовал событие PagesOnChangeActivePage, а не PagesOnChangedActivePage. Первое событие автоматически срабатывает при изменении активной страницы. В связи с этим:
3) Не совсем понимаю, зачем в wnd_BaseDBEditOnPrepare вызывать
if (Pages.ActivePage.Name == 'Page1'){ PagesOnChangedActivePage(Pages) }
4) Кнопка "Добавить" может быть неактивна из-за того, что в окне реестра не определён атрибут ParentItemID. Попробуйте его передавать при обновлении дочернего реестра.
Определил атрибут ParentItemID:
SetAttribute(wcExpence.Window,'ParentItemID','SiteID');
кнопка "добавить" стала доступна. Но окно редактирования всё равно не инициализируется и датасет этого окна не открывается, а он, если я правлиьно понимаю, должен не просто открываться, а открываться в определенном режиме в зависимости от нажатой кнопки.
"SSV" написал:4) А можно подробнее?
С учётом Вашего кода, думаю, получится где-то так:
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'); }
Это при условии, что в запросе дочернего реестра создан параметр с названием S_ID и фильтр с кодом S_ID сравнения соответствующей колонки с этим параметром. Попробуйте это вместо кода
DatasetCashflow.Close(); ApplyDatasetFilter(DatasetCashflow, 'S_ID', S_ID, true); DatasetCashflow.Open();
Попробуйте всё-таки выполнять обновление реестра не на OnPrepare окна редактирования, а в обработчике события OnChangeActivePage объекта Pages.
Всё сделал, как Вы написали, но окно редактирования этого дочернего реестра всё равно не работает
(
SetAttribute(wcExpence.Window,'EditWindowUSI', <strong>'wnd_SiteExpEdit'</strong>);
).
Оно открывается, но в поля редактирования ничего нельзя впечатать и ни одно поле не инициализируется текущими значениями.
Это реализовано в функционале базовых окон реестра и редактирования: во-первых, события по нажатию кнопок "Добавить" и "Изменить" обрабатываются по-разному. Окну редактирования передаётся атрибут RecordID, и если он содержит пустое значение (первый случай), датасет окна устанавливается в режим добавления записи (Dataset.Append()). Если же этот атрибут не пустой, датасет устанавливается в режим редактирования (Dataset.Edit()).
Установка атрибутов перед вызовом окна редактирования по факту осуществляется с помощью функции AddRequiredValuesToDictionary (во всех случаях), но она в разных случаях получает разные атрибуты. Посмотрите её текст в скрипте scr_BaseGridAreaUtils, а также тексты функций, которые её вызывают: GetAddDataAttributes, GetCopyDataAttributes, GetEditDataAttributes и т.д.
Можете выложить все сервисы, которые касаются окна редактирования и его компонент? Попытаюсь разобраться, почему не работает.
Хм, а может я не всё корректно тут изложил. Дело в том, что в окне редактирования, на котором лежит объект Pages, есть еще один даталинк, который и содержит датасет с данными из дочернего реестра. Даталинк с тем же датасетом есть в окне редактирования дочернего реестра. Может здесь проблема? Может эти датасеты нужно как то увязать?
Да, в контекстном меню дерева сервисов есть возможность сохранить сервис в файл.
Что касается второго даталинка, Вы как-то с ним работаете в скрипте основного окна? Если нет, то не думаю, чтобы он как-то повлиял.
Есть несколько вопросов.
Я имел в виду все сервисы, касающиеся окна редактирования, включая таблицы, окна, скрипты, запросы, датасеты.
Кроме того, архив полностью не распаковывается, извлекаются только два датасета и окно. Можете выложить их повторно?
Также прошу уточнить версию Terrasoft. Мне удалось определить только, что она ниже 3.1.0.
И последнее: при загрузке wnd_SiteExpenceEdit у меня пропадает окно wnd_BaseDBEdit. Значит ли это, что Вы получили это окно путём редактирования базового окна?
Заранее благодарен за помощь.
Мне кажется, для корректной работы (если в остальном окно работает нормально) должно быть достаточно такого текста в обработчике PagesOnChangedActivePage:
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'); } }
По крайней мере, с таким кодом у меня нормально добавлялись новые записи в дочерний реестр.
Что касается остальных функций, то для корректного редактирования Вам необходимо создать фильтр с кодом ID (и соответствующий параметр) в запросе sq_CashflowExp, а для удаления - указать в качестве ключевого поля поле ID в датасете ds_CashflowExp.
Записи начали удаляться.
А вот остальные функции так и не заработали - не редактируются поля Сумма и Описание, только дату можно выбрать. Кроме этого заметил еще вот что - при повторном вызове окна wnd_SiteExpenceEdit в одном сеансе работы программы, у него пропадает заголовок и названия полей (Дата, Сумма, Описание). Получается, что датасет в даталинке этого окна вообще куда то пропадает?
Попытался нажимать кнопку ОК в окне wnd_SiteExpenceEdit - в скрипте scr_BaseDBEditUtils в функции CheckRequiredDataControl, на строке
var Condition = !IsEmptyValue(DataField.Value) && (DataField.Value != 0);
выпадает ошибка о том, что источник данных ds_CashflowExp не открыт. При повторном вызове этого окна и попытке нажать ОК выпадает ошибка о том, что датасет равен NULL уже на строке
var DataField = DatasetLink.Dataset.DataFields(Control.DataFieldName);
в той же самой функции. Как такое может быть? И почему датасет может не открываться?
После добавления в обработчик события wnd_BaseDBEditOnPrepare окна wnd_SiteExpenceEdit строки
scr_BaseDBEdit.wnd_BaseDBEditOnPrepare(Window);
всё заработало.
Олег, спасибо за помощь.
Но всё таки осталась неуверенность - у меня пока не сложился в голове алгоритм последовательности действий в таких ситуациях. По большому счету он как раз меня больше всего интересовал. Моей целью было не получить готовое решение, а получить информацию по правильной последовательности и обязательности шагов.
Видимо, у меня всё работало, потому что я не создавал для wnd_SiteExpenceEdit своего скрипта, а в архиве его не было. В этом случае используется базовый скрипт.
По поводу инициализации. В основном инициализация окна извне (из другого окна, по какому-либо событию) заключается в передаче окну необходимых атрибутов и вызова его метода Prepare (во время обработки которого завершается инициализация). Список атрибутов может отличаться для разных окон, в зависимости от их предназначения и дальнейшей функциональности. Например, для реестра детали обязательно нужно указать EditWindowUSI - USI окна редактирования, ParentItemFieldName - название родительского поля, ParentItemID - ID родительского элемента. Иногда необходимо скрыть фрейм кнопок реестра - за это отвечает атрибут HideButtonsFrame. Если в окне реестра явно не указан датасет, необходимо заполнить атрибут DatasetUSI. И так далее. Например:
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; }
Если необходимо, окна деталей и их датасеты можно запомнить в глобальные переменные скрипта, как в примере выше.
Некоторые атрибуты достаточно передать один раз (в процессе работы с окном они не меняются), но есть и такие (например, ParentItemID), которые нужно обновлять гораздо чаще. Поэтому в таких случаях создают отдельную функцию обновления окна, которая включает в себя функцию инициализации, если окно ещё не проинициализировано. Также эта функция присваивает атрибутам новые значения и обновляет датасет окна. Например:
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'); }
В принципе, для обновления окна детали в большинстве случаев достаточно тех действий, которые выполняет функция RefreshCommonDetail из скрипта scr_WorkspaceUtils.
Пример вызова окна редактирования:
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);
Всё происходит примерно так же: устанавливаем значения атрибутов, значений по умолчанию (которые на самом деле можно записать в атрибут с кодом DefaultValues) и вызываем окно. Рекомендую подробнее ознакомиться с кодом функции ShowEditWindowEx, некоторые её конструкции полезно использовать при написании своих функций.
Надеюсь, это описание будет Вам полезно. Примеры кода взяты из скрипта scr_AccountWorkspace.