При создании сложной системы может потребоваться связывать карточки, т.е. сделать так, чтобы одна карточка, порождала другие, а при удалении главной карточки, карточки, связанные с ней удалялись тоже.
Например, создается карточка Проблемы (родительская), а к ней должна быть прикреплена карточка Решения (дочерняя).
Для этого необходимо следующее:
1. Создать в схеме данных карточки новое поле, которое будет представлять собой ссылку на карточку (refcardid) и в типе ссылки указать "Hard".
2. Положить на форму контрол карточки и привязать его к созданному полю (CardLink).
Данный метод можно использовать и с табличным контролом, привязав столбец к настроенному подобным образом полю в табличной секции карточки.
Мы обсуждаем следующие темы: Docsvision, редактирование и создание карточек документов, процесс, написание кода на C#
Темы обсуждений
бизнес-календарь
(2)
бизнес-процесс
(1)
блог
(3)
виды
(2)
дайджест
(1)
дополнительные сборки
(1)
изображение
(1)
карточки
(4)
кнопка
(1)
конструктор
(9)
литература
(1)
навигатор
(1)
настройка представлений
(1)
нумератор
(2)
ошибки
(3)
полезность
(1)
разметки
(2)
роли
(1)
сервер
(1)
сервис
(1)
скрипт
(12)
состояния
(1)
табличный контрол
(3)
уведомления
(1)
attribute
(1)
C#
(11)
DevExpress
(1)
DVCardManager
(2)
DVExplorer
(1)
HowTo
(18)
property
(3)
xml
(1)
XSLT
(1)
Поиск блогу
пятница, 7 октября 2011 г.
пятница, 9 сентября 2011 г.
Недавно компания DocsVision запустила свой портал технической поддержки. В настоящий момент в нем есть специальная ветка для статей и вопросов по Конструктору Решений. Найти его можно по этой ссылке.
Несмотря на то, что часть статей взята из этого блога, там есть и статьи, которые не опубликованы здесь.
В дальнейшем часть из них будет перенесена в блог.
Свои вопросы можно по прежнему оставлять в блоге. Отвечать на них буду по возможности оперативно.
Несмотря на то, что часть статей взята из этого блога, там есть и статьи, которые не опубликованы здесь.
В дальнейшем часть из них будет перенесена в блог.
Свои вопросы можно по прежнему оставлять в блоге. Отвечать на них буду по возможности оперативно.
понедельник, 8 августа 2011 г.
Рассылка уведомлений
В версии конструктора 4.5 есть сервис уведомлений.
С его помощью можно настроить рассылку уведомлений в виде ярлыка или почтового сообщения на изменения полей карточки. На данный момент уведомления рассылаются при изменении поля и последующем сохранении карточки. В связи с этим есть проблема, если необходимо отправить уведомление о смене состояния карточки. Для того, чтобы отправить такое уведомление, придется в скрипте карточки, меняющем ее состояние прописать принудительное изменение значения контрола состояния через PropertyController.UpdateProperty, либо (что будет оптимальнее при необходимости отправки нового состояния в уведомлении) записывать новое состояние в скрытый строковый контрол. Например, вот так:
С его помощью можно настроить рассылку уведомлений в виде ярлыка или почтового сообщения на изменения полей карточки. На данный момент уведомления рассылаются при изменении поля и последующем сохранении карточки. В связи с этим есть проблема, если необходимо отправить уведомление о смене состояния карточки. Для того, чтобы отправить такое уведомление, придется в скрипте карточки, меняющем ее состояние прописать принудительное изменение значения контрола состояния через PropertyController.UpdateProperty, либо (что будет оптимальнее при необходимости отправки нового состояния в уведомлении) записывать новое состояние в скрытый строковый контрол. Например, вот так:
CardData cStates = Session.CardManager.GetCardData(new Guid("{7984F2CE-9345-4C59-B66B-7125DD9195A1}"));// Получаем справочник ролевой модели. В нем хранятся состояния PropertyController.UpdateProperty("СтрокаСостояния",cStates.Sections[new Guid("{521B4477-DD10-4F57-A453-09C70ADB7799}")].Rows[DomainObject.StateId].GetString("DefaultName"));// Получаем название текущего состояния и записываем его в контрол.
четверг, 21 июля 2011 г.
Изменение вида карточки
Предположим, что на карточке лежит контрол "Вид".
Опытным путем я установил, что при изменении значения в нем, само изменение вида карточки происходит уже после события ControlValueChanged.
Это означает то, что при написании ControlValueChanged для этого контрола нужно использовать PropertyController.GetPropertyValue("НазваниеКонтролаВида") вместо DomainObject.KindId, чтобы получить в скрипте новое значение вида.
Опытным путем я установил, что при изменении значения в нем, само изменение вида карточки происходит уже после события ControlValueChanged.
Это означает то, что при написании ControlValueChanged для этого контрола нужно использовать PropertyController.GetPropertyValue("НазваниеКонтролаВида") вместо DomainObject.KindId, чтобы получить в скрипте новое значение вида.
вторник, 12 июля 2011 г.
Скрипт на привязку карточки с табличному контролу.
Всем привет :-)
В одну из составляющих моей разработки решения"Управление совещаниями", входит объединение всех трёх карточек в единую работающую систему. Для этого мне требуется написать несколько скриптов на событие AddButtonClick табличного контрола. Мои познания в ООП находятся на уровне основных понятий, поэтому самостоятельно выполнить поставленную задачу будет крайне трудно, и если уважаемые разработчики помогут мне с преодолением этой проблемы, я буду им очень благодарен за проявленное содействие в достижении личных и организационных успехов.
Итак, задача:
В основной карточке "Совещание" ( Card 1 ) в таблице с вопросами повестки, при нажатии на добавить "+", должна появляться новая карточка "Вопросы повестки" ( Card 2 ). Так же, при каждом нажатии на добавить "+" карточка должна обновляться.
{
object newCard = Session.CardManager.CreateCard(new Guid("{5763AAF2-BF9B-4373-AF1B-6360EF4A2FFA}"));
}
но при загрузке карточки он выдаёт ошибку, что "Данный метод не поддерживается".
Вопрос : Какой скрипт будет выполнять поставленную задачу?
Спасибо)
Темы, поднимаемые в сообщении:
карточки,
конструктор,
табличный контрол
четверг, 30 июня 2011 г.
Как подключать сборки в конструкторе DocsVision
Рано или поздно придется столкнуться с подключением сборок в конструкторе.
Находятся все сборки по пути Windows/assembly/GAC_MSIL
Каталог скрытый, поэтому для доступа к нему через эксплорер необходимо включить отображение скрытых файлов и папок в свойствах папки.
Каждая сборка лежит в отдельной папке, поэтому подключать их придется по одной.
Из-за особенностей Конструтора у вас не получится подключить сборки сразу из assembly, поэтому скопируйте сначала нужные сборки в отдельную папку и уже оттуда подключайте. Но лучше удалить из GAC_MSIL скрытый файл "Desktop.ini". После этого папки со сборками станут видны из конструктора и их не придется никуда копировать. Также одном из плюсов данного способа является тот факт, что при переносе решения на другую машину, вам не придется заново прописывать пути к сборкам.
Для подключения сборки кликните на "+" в нижней таблице "Используемые дополнительные сборки" в окне редактирования скриптов конструктора, выберите нужную сборку и добавьте ее в таблицу.
Находятся все сборки по пути Windows/assembly/GAC_MSIL
Каталог скрытый, поэтому для доступа к нему через эксплорер необходимо включить отображение скрытых файлов и папок в свойствах папки.
Каждая сборка лежит в отдельной папке, поэтому подключать их придется по одной.
Из-за особенностей Конструтора у вас не получится подключить сборки сразу из assembly, поэтому скопируйте сначала нужные сборки в отдельную папку и уже оттуда подключайте. Но лучше удалить из GAC_MSIL скрытый файл "Desktop.ini". После этого папки со сборками станут видны из конструктора и их не придется никуда копировать. Также одном из плюсов данного способа является тот факт, что при переносе решения на другую машину, вам не придется заново прописывать пути к сборкам.
Для подключения сборки кликните на "+" в нижней таблице "Используемые дополнительные сборки" в окне редактирования скриптов конструктора, выберите нужную сборку и добавьте ее в таблицу.
Темы, поднимаемые в сообщении:
дополнительные сборки,
конструктор,
HowTo
Получение данных выделенной строки из таблицы
Вывод выделенной строки оказался весьма нетривиальным заданием.
Данный фрагмент кода выведет в MessageBox содержимое выделенной строки в табличном контроле с названием "Журнал заявки".
Для работы скрипта нужно прописать в using:
Возможно, что-то еще...
а также подключить сборки DevExpress. А именно
DevExpress.XtraLayout.9.2.dll
DevExpress.XtraGrid.9.2.dll
DevExpress.Data.9.2.dll
DevExpress.Utils.9.2.dll
Данный фрагмент кода выведет в MessageBox содержимое выделенной строки в табличном контроле с названием "Журнал заявки".
LayoutHelper layoutHelper = new LayoutHelper(CardControl.LayoutControl, CardControl.BarManager, Session, CardData.Type.Id); DocsVision.BackOffice.View.WinForms.LayoutItems.ICustomPropertyItem propertyItem = layoutHelper.GetCustomPropertyItem("Журнал заявки"); var refMapper = new CardPropertyDescriptionMapper(Session); DocsVision.BackOffice.Model.CardProperties.Entities.CardPropertyTable cpt = null; foreach (DocsVision.BackOffice.Model.Layouts.Entities.CardPropertyTableDescription refPropertyTableDesc in refMapper.FindTableProperties(CardData.Type.Id)) { if (refPropertyTableDesc.Name == "Журнал заявки") { var propertyMapper = new CardPropertyMapper(Session, CardData.Id, DomainObject.CustomPropertiesSectionId); cpt = propertyMapper.FindTable(refPropertyTableDesc); break; } } System.Reflection.Assembly asm = System.Reflection.Assembly.Load("DocsVision.BackOffice.View, Version=4.5.0.0, Culture=neutral, PublicKeyToken=7148afe997f90519"); Type tableType = asm.GetType("DocsVision.BackOffice.View.WinForms.PropertyControls.TablePropertyControl"); var propInfo = tableType.GetProperty("GridView"); object ooo = propInfo.GetValue(propertyItem.Control, System.Reflection.BindingFlags.NonPublic, null, null, System.Globalization.CultureInfo.InvariantCulture); DocsVision.BackOffice.View.WinForms.Controls.GridExView gridExView = ooo as DocsVision.BackOffice.View.WinForms.Controls.GridExView; DevExpress.XtraGrid.Views.Grid.GridView gridView = gridExView as DevExpress.XtraGrid.Views.Grid.GridView; object key = ((System.Data.DataRowView)gridView.GetFocusedRow()).Row[gridExView.KeyField]; foreach (DocsVision.BackOffice.Model.CardProperties.Entities.CardPropertyTableRow row in cpt.Rows) { if (row.Key == (Guid)key) { string message = ""; foreach (DocsVision.BackOffice.Model.CardProperties.Entities.CardProperty cellProp in row.Cells) { object val = cellProp.Value; message += val == null ? "null" : val.ToString(); message += " "; } MessageBox.Show(message); } }
Для работы скрипта нужно прописать в using:
using DocsVision.Platform.WinForms.DataSource; using DocsVision.BackOffice.Model.CardProperties.DataAccess;
Возможно, что-то еще...
а также подключить сборки DevExpress. А именно
DevExpress.XtraLayout.9.2.dll
DevExpress.XtraGrid.9.2.dll
DevExpress.Data.9.2.dll
DevExpress.Utils.9.2.dll
Темы, поднимаемые в сообщении:
конструктор,
скрипт,
табличный контрол,
C#,
DevExpress,
HowTo
Добавление новой строки в табличный контрол из скрипта
Оговорю сразу, что данный метод работает, если для табличного контрола создана отдельная секция в карточке, так как добавление происходит через добавление записи в секцию.
Рассмотрим на примере таблицы, содержащей 3 столбца: Дату, идентификатор сотрудника и некоторый текст.
в приведенном скрипте:
secComment - это идентификатор табличной секции(Guid);
comment - какая-то строка(string)
Скрипт записывает текущую дату, пользователя, который открыл карточку в данный момент и некоторый текст.
Рассмотрим на примере таблицы, содержащей 3 столбца: Дату, идентификатор сотрудника и некоторый текст.
в приведенном скрипте:
secComment - это идентификатор табличной секции(Guid);
comment - какая-то строка(string)
Скрипт записывает текущую дату, пользователя, который открыл карточку в данный момент и некоторый текст.
Guid g = Guid.NewGuid(); CardData.Sections[secComment].BeginUpdate(); RowData newComment = CardData.Sections[secComment].CreateRow(g); newComment.SetString("Текст", comment); newComment.SetGuid("Автор", new EmployeeMapper(Session).GetCurrentUserId()); newComment.SetDateTime("Дата", DateTime.Now); CardData.Sections[secComment].EndUpdate();
Темы, поднимаемые в сообщении:
конструктор,
скрипт,
табличный контрол,
HowTo
суббота, 21 мая 2011 г.
Смена атрибутов контрола из скрипта. На примере атрибута ReadOnly
Данный скрипт полезен в тех случаях, когда, например, измененное значение одного контрола влияет на доступность другого.
using System; using System.Windows.Forms; using DocsVision.Platform.ObjectManager; using DocsVision.BackOffice.View.WinForms; using DocsVision.BackOffice.Model; using DocsVision.BackOffice.Model.Layouts.DataAccess; using DocsVision.BackOffice.Model.Base.Entities; using DocsVision.BackOffice.Model.CardProperties.Entities; using DocsVision.BackOffice.Model.Layouts.Entities; using DocsVision.BackOffice.Model.RoleModel.DataAccess; using DocsVision.BackOffice.Model.RoleModel.Entities; using DocsVision.BackOffice.View.WinForms.Helpers; private void cardControl_AfterActivate(System.Object sender, System.EventArgs e) { CardProperty prop = GetCardProperty("имя контрола"); CardPropertyDescription.LayoutAttributeSet attrSet = prop.Description.GetLayoutAttributes(CardControl.DomainObject.SelectedLayoutId); attrSet.ReadOnly = true; PropertyController.Refresh(); } //Поиск контрола с нужным именем private CardProperty GetCardProperty(string propertyName) { foreach (CardProperty property in PropertyController.CardProperties) { if (property.Name == propertyName) return property; } return null; }
среда, 11 мая 2011 г.
Перезапуск сервисов из командной строки
Думаю, что многие сталкивались с проблемой, что какие-то изменения, внесенные в структуру DV требовали перезапуска серверов, SQL и IIS. На это уходит много времени, так как надо полазать по различным административным менюшкам и покликать много кнопок.
Я предлагаю вариант, когда перезапуск всех служб можно будет делать по двойному клику на ярлык на рабочем столе.
1. создаем новый текстовый файл.
2. в тело пишем
NET stop DVStorageServer45
NET stop WFServer45
NET stop MSSQL$SQLEXPRESS
IISReset
NET start MSSQL$SQLEXPRESS
NET start DVStorageServer45
NET start WFServer45
3. сохраняем файл на рабочий стол под именем Reset.bat и в свойствах файла выставляем "Запускать от имени Администратора". Иногда для этого приходится создать ярлык на этот батник и в его свойствах поставить запуск от имени администратора.
4. наслаждаемся перезапуском в один клик.
P.S. Возможно, что SQL сервер у вас называется не SQLEXPRESS. В таком случае либо просто удалите из батника строку перезапуска SQL (Обычно такой перезапуск не требуется), либо впишите свое название сервера.
Я предлагаю вариант, когда перезапуск всех служб можно будет делать по двойному клику на ярлык на рабочем столе.
1. создаем новый текстовый файл.
2. в тело пишем
NET stop DVStorageServer45
NET stop WFServer45
NET stop MSSQL$SQLEXPRESS
IISReset
NET start MSSQL$SQLEXPRESS
NET start DVStorageServer45
NET start WFServer45
3. сохраняем файл на рабочий стол под именем Reset.bat и в свойствах файла выставляем "Запускать от имени Администратора". Иногда для этого приходится создать ярлык на этот батник и в его свойствах поставить запуск от имени администратора.
4. наслаждаемся перезапуском в один клик.
P.S. Возможно, что SQL сервер у вас называется не SQLEXPRESS. В таком случае либо просто удалите из батника строку перезапуска SQL (Обычно такой перезапуск не требуется), либо впишите свое название сервера.
Скрипт смены состояния карточки из бизнес-процесса
К сожалению, стандартными процедурами бизнес-процесса невозможно изменить состояние карточки. Для изменения состояния нужно поставить элемент "Скрипт" и написать в нем код, представленный ниже.
Важно помнить о следующей структурной особенности состояний: они различны у каждого вида карточки, поэтому сначала надо получать текущий вид карточки, а затем выбирать соответствующее ему состояние.
Важно помнить о следующей структурной особенности состояний: они различны у каждого вида карточки, поэтому сначала надо получать текущий вид карточки, а затем выбирать соответствующее ему состояние.
// подключение системных библиотек using System; using System.Xml; // подключение библиотек СУБП using DocsVision.Workflow.Objects; using DocsVision.Workflow.Runtime; using DocsVision.Workflow.Gates; using DocsVision.Platform.HelperAPI; using DocsVision.Platform.ObjectManager; namespace DVScriptHost { class DVScript { // стандартная функция, которая будет вызвана подсистемой СУБП // // входные параметры функции: // // process - информация о процессе. содержит коллекции // Gates - коллекция шлюзов процесса // Variables - коллекция переменных процесса // passInfo - информация о текущем проходе // private string state = "Согласование с контрагентом"; //Название состояния, в которое мы хотим перевести карточку private DVGate m_DVGate; public void Execute (DocsVision.Workflow.Runtime.ProcessInfo process, PassState passInfo) { try { //Получаем ссылку на карточку, у которой надо сменить состояние. В данном случае она хранится в переменной процесса, которая называется "Инициирующий договор" ProcessVariable pvCard = process.GetVariableByName("Инициирующий договор"); DVCard dvCard = (DVCard)pvCard.Value; //получаем шлюз m_DVGate = (DVGate)process.Gates[DVGate.GateID]; // получаем сессию UserSession oSes = m_DVGate.Session; //Получаем данные карточки CardData card = oSes.CardManager.get_CardData(dvCard.ID); //Получаем ссылку на секцию "Основная информация". Так как карточка стандартная, то гуид берем из справочника в предыдущем посте. В противном случае - из DVExplorer. SectionData mainInfo = card.Sections["8C77892A-21CC-4972-AD71-A9919BCA8187"]; //Получаем ссылку на справочник типов. Гуид берем из справочника в предыдущем посте. CardData RefTypes = oSes.CardManager.get_DictionaryData("BE14D55D-92B7-4345-AD10-32588981F83D"); //Получаем тип карточки из справочника типов RowData currentType = RefTypes.Sections["49AD5A2D-17EC-46E2-A49E-C58D0BBD9C1A"].Rows[mainInfo.FirstRow.get_Value("Type")]; //Устанавливаем состояние карточки, найдя его по имени и в соответствии с типом карточки mainInfo.FirstRow.set_Value("DocState", currentType.ChildRows.GetItemByValue("Name", state).ID); } catch (Exception ex) { // запись в журнал ошибки исполнения process.LogMessage("Ошибка выполнения скрипта:" + ex.Message); } return; } } }
Темы, поднимаемые в сообщении:
бизнес-процесс,
скрипт,
состояния,
C#,
HowTo
Описание полей стандартных карточек.
Думаю, что многие из вас сталкивались с проблемой отсутствия документации по структуре стандартных справочников и карточек. Я сам лично довольно долго мучился в поисках подобной информации, но недавно мне удалось найти очень полезный документ, в котором содержатся описания всех полей стандартных карточек.
Также, благодаря этому документу я выяснил, что у всех стандартных карточек и справочников постоянные идентификаторы, которые не зависят от того, где установлена система. Они тоже приведены в этом файле.
Описание полей стандартных карточек.doc
Также, если кому-то нужна литература по C#, то выкладываю самоучитель: Секунов С.Ю. - Самоучитель С# - 2001.pdf
И также самоучитель по xml: samou4itel_xml.rar
Также, благодаря этому документу я выяснил, что у всех стандартных карточек и справочников постоянные идентификаторы, которые не зависят от того, где установлена система. Они тоже приведены в этом файле.
Описание полей стандартных карточек.doc
Также, если кому-то нужна литература по C#, то выкладываю самоучитель: Секунов С.Ю. - Самоучитель С# - 2001.pdf
И также самоучитель по xml: samou4itel_xml.rar
Темы, поднимаемые в сообщении:
карточки,
литература,
полезность
Новости блога. Дополнительные возможности при просмотре блога.
Благодаря нововведениям платформы Blogger, наш блог теперь можно просматривать в различных видах, используя страницу видов. Ссылка на данную страницу теперь всегда доступна из списка полезных ссылок справа.
Подробнее об этой фиче можно почитать тут.
Также я добавил возможность подписки на новые сообщения в блоге. Для того, чтобы подписаться, достаточно ввести свой адрес электронной почты в форму, которая находится внизу меня справа. Не забудьте подтвердить подписку, перейдя по ссылке, которую вы получите в письме сразу после ввода адреса почты.
Подробнее об этой фиче можно почитать тут.
Также я добавил возможность подписки на новые сообщения в блоге. Для того, чтобы подписаться, достаточно ввести свой адрес электронной почты в форму, которая находится внизу меня справа. Не забудьте подтвердить подписку, перейдя по ссылке, которую вы получите в письме сразу после ввода адреса почты.
четверг, 10 марта 2011 г.
Добавление пользовательского свойства карточки в представление
Новые карточки создаются изначально на свойствах, позже, конечно, карточку переводят на поля для удобства работы с ней, но не всегда полностью. Также, если Вы создали новый вид стандартной карточки и напичкали ее пользовательскими свойствами, то скорее всего встанет проблема доступа к ним.
Посмотрим, как можно обратиться к такому свойству при настройке представлений.
Пусть у нас есть карточка договора, настроенная как дополнительный вид входящего документа через справочник типов. В карточке договора используется часть полей из карточки входящего документа (Тема, дата создания и пр.), но также имеются пользовательские свойства (Примечание, сумма договора, сумма аванса, контрагент и его адрес и тд.). Задача усложняется, если пользовательские настройки вида содержат табличный контрол.
В примере Договора в табличном контроле 2 столбца: Контрагент и его адрес.
Задача: вывести в представлении фамилию контрагента. Вот так:
Сначала делаем все, как и при обычном создании представления: создаем представление, добавляем колонки.
Затем нужно сделать следующие присоединения:
1.
Привязываем свойство с названием "Контрагент", принадлежащее данной карточке (InstanceID)
2.
Не очевидная привязка выбранных значений. Нужна, так как столбец табличного контрола представляет собой массив. После этого в после "Выбранное значение" будут находиться идентификаторы контрагентов
3.
Получение по Идентификатору из выбранного значения информации о контрагенте.
После перечисленных привязок можно сделать присвоение колонке значения поля Фамилия из привязанной карточки контрагентов:
P.S. Если есть проблема с добавлением простого (не табличного) пользовательского свойства в представление, дайте знать в комментах. В таком случае напишу и про них.
Посмотрим, как можно обратиться к такому свойству при настройке представлений.
Пусть у нас есть карточка договора, настроенная как дополнительный вид входящего документа через справочник типов. В карточке договора используется часть полей из карточки входящего документа (Тема, дата создания и пр.), но также имеются пользовательские свойства (Примечание, сумма договора, сумма аванса, контрагент и его адрес и тд.). Задача усложняется, если пользовательские настройки вида содержат табличный контрол.
В примере Договора в табличном контроле 2 столбца: Контрагент и его адрес.
Задача: вывести в представлении фамилию контрагента. Вот так:
Сначала делаем все, как и при обычном создании представления: создаем представление, добавляем колонки.
Затем нужно сделать следующие присоединения:
1.
Привязываем свойство с названием "Контрагент", принадлежащее данной карточке (InstanceID)
2.
Не очевидная привязка выбранных значений. Нужна, так как столбец табличного контрола представляет собой массив. После этого в после "Выбранное значение" будут находиться идентификаторы контрагентов
3.
Получение по Идентификатору из выбранного значения информации о контрагенте.
После перечисленных привязок можно сделать присвоение колонке значения поля Фамилия из привязанной карточки контрагентов:
P.S. Если есть проблема с добавлением простого (не табличного) пользовательского свойства в представление, дайте знать в комментах. В таком случае напишу и про них.
Темы, поднимаемые в сообщении:
настройка представлений,
HowTo,
property
воскресенье, 6 марта 2011 г.
Смена состояния карточки из скрипта
На первый взгляд простое задание - сменить состояние карточки из скрипта. Вроде и у карточки стандартная кнопка для смены состояния есть, но и тут не обходится без бубна.
На данный момент простого способа сменить состояние из скрипта я не нашел. Единственный способ требует знания гуида конечного состояния. Данный идентификатор не доступен ни в одном из стандартных справочником и контекстных меню, поэтому приходится идти в обход.
Создаем строковый контрол на карточке. Затем на какую-нибудь кнопку ставим команду, записывающую в этот котрол значение из DomainObject.StateManager.CurrentStateId. (В моем случае по какой-то причине на активацию карточки поставить не удалось, только на кнопку или команду меню). Сохраняем карточку, закрываем конструктор.
Открываем карточку в навигаторе, прогоняем состояние карточки стандартной кнопкой "Сменить состояние" до нужного состояния и выполняем скрипт, записывающий состояние в строку. Вот он наш искомый гуид.
Далее в конструкторе в нужном Вам месте пишем:
Вместо "fce438e8-d38c-4552-86d0-36d464920265" конечно же нужно поставить нужный гуид.
P.S. Я полагаю, что возможно как-то менять состояние карточки проще, используя команду DomainObject.ChangeCardState(StateMachineBranch branch), но я так и не смог понять, как ей пользоваться. Если кто-то разберется, то очень хотел бы получить совет в комментах.
На данный момент простого способа сменить состояние из скрипта я не нашел. Единственный способ требует знания гуида конечного состояния. Данный идентификатор не доступен ни в одном из стандартных справочником и контекстных меню, поэтому приходится идти в обход.
Создаем строковый контрол на карточке. Затем на какую-нибудь кнопку ставим команду, записывающую в этот котрол значение из DomainObject.StateManager.CurrentStateId. (В моем случае по какой-то причине на активацию карточки поставить не удалось, только на кнопку или команду меню). Сохраняем карточку, закрываем конструктор.
Открываем карточку в навигаторе, прогоняем состояние карточки стандартной кнопкой "Сменить состояние" до нужного состояния и выполняем скрипт, записывающий состояние в строку. Вот он наш искомый гуид.
Далее в конструкторе в нужном Вам месте пишем:
DomainObject.StateManager.SetCurrentState(new Guid("fce438e8-d38c-4552-86d0-36d464920265")); CardControl.RefreshLayout();
Вместо "fce438e8-d38c-4552-86d0-36d464920265" конечно же нужно поставить нужный гуид.
P.S. Я полагаю, что возможно как-то менять состояние карточки проще, используя команду DomainObject.ChangeCardState(StateMachineBranch branch), но я так и не смог понять, как ей пользоваться. Если кто-то разберется, то очень хотел бы получить совет в комментах.
среда, 2 марта 2011 г.
Вызов картинки с локального диска, запись в стандартный контрол типа "изображение"
System.Drawing.Image image = System.Drawing.Image.FromFile(@"c:\Img.jpg");
PropertyController.UpdateProperty("imageControl", image); //imageControl - имя контрола типа "Изображение"
CardControl.RefreshLayout();
Темы, поднимаемые в сообщении:
изображение,
скрипт,
C#,
HowTo
четверг, 24 февраля 2011 г.
Работа блога
Думаю, что все заметили раздел "Полезные ссылки".
Он будет время от времени дополняться. Сегодня была добавлена ссылка на довольно обширную базу знаний о DocsVision от компании-партнера TeamLead.
Также существует страница с частыми вопросами по работе блога: FAQ. К ней в комментариях можно оставлять свои вопросы по работе блога и его настройкам. Также там можно оставлять свои пожелания по добавлению/изменению/удалению каких-то функций в блоге.
Он будет время от времени дополняться. Сегодня была добавлена ссылка на довольно обширную базу знаний о DocsVision от компании-партнера TeamLead.
Также существует страница с частыми вопросами по работе блога: FAQ. К ней в комментариях можно оставлять свои вопросы по работе блога и его настройкам. Также там можно оставлять свои пожелания по добавлению/изменению/удалению каких-то функций в блоге.
вторник, 22 февраля 2011 г.
DVCardManager
Недавно столкнулся с проблемой, что не мог загрузить библиотеку в базу при помощи CardManager.
При более детальном рассмотрении выяснилось, что для нормальной работы структура локальной базы должны соответствовать структуре базы на сервере, т.е. должна иметь те же системные библиотеки.
Следовательно, кроме "тестовой" должны быть добавлены следующие библиотеки:
.
После этого будут работать функции Update Database и Upload Library.
При более детальном рассмотрении выяснилось, что для нормальной работы структура локальной базы должны соответствовать структуре базы на сервере, т.е. должна иметь те же системные библиотеки.
Следовательно, кроме "тестовой" должны быть добавлены следующие библиотеки:
.
После этого будут работать функции Update Database и Upload Library.
понедельник, 21 февраля 2011 г.
Вывод значения нумератора в дайджест
Иногда нужно вывести значения из нумератора в дайджест. Например, нужно вывести регистрационный номер документа.
На данный момент не удастся обойтись без создания дополнительного контрола. Нужно добавить новый строчный контрол на форму и сделать его невидимым.
Далее, если, например, вы пользуетесь кодом, опубликованным в этом посте, для автоматической генерации номера, то в конец скрипта нужно добавить всего одну строчку:
В дайджест добавляем что-то вроде этого:
Результат будет выглядеть так:
P.S. Если Вы не используете автоматическое заполнение нумератора, то придется написать еще обращение к нумератору через Mapper и вставить это в AfterActivate
На данный момент не удастся обойтись без создания дополнительного контрола. Нужно добавить новый строчный контрол на форму и сделать его невидимым.
Далее, если, например, вы пользуетесь кодом, опубликованным в этом посте, для автоматической генерации номера, то в конец скрипта нужно добавить всего одну строчку:
PropertyController.UpdateProperty("НомерПрописью",number.Number);// в скрытое поле записываем номер в виде строки
В дайджест добавляем что-то вроде этого:
Номер:
Результат будет выглядеть так:
P.S. Если Вы не используете автоматическое заполнение нумератора, то придется написать еще обращение к нумератору через Mapper и вставить это в AfterActivate
суббота, 12 февраля 2011 г.
Баг
Ошибка: Создаем несколько разметок для разных видов карточки. При редактировании каждой разметки (добавлении контролов), причем только в случае использования многозакладочности, имена контролам могут присвоиться одинаковые для разных разметок. КР сначала не видит ошибку. Но при закрытии КР и повторном входе выдает ошибку о нескольких контролах с одинаковым именем.
Способ решения: при добавлении контролов в разные разметки карточки нужно не допускать совпадания имен контролов, иначе карточка станет недоступна для редактирования. При перезагрузке КР и навигатора карточка загружается без последних изменений.
Способ решения: при добавлении контролов в разные разметки карточки нужно не допускать совпадания имен контролов, иначе карточка станет недоступна для редактирования. При перезагрузке КР и навигатора карточка загружается без последних изменений.
Темы, поднимаемые в сообщении:
конструктор,
ошибки,
разметки
Продолжение рассмотрения пространства имен BusinessCalendar.
Пару постов назад я начал писать про пространство имен DocsVision.BackOffice.Model.BusinessCalendar.Entities. Упоминал, что в нем содержатся 2 перечислимых типа DayType и TimeType.
Для справки: Перечислимый тип - это тип данных, переменные которого могут принимать значения заранее заданные пользователем. Например, можно создать тип "Animals", и возможными значениями у этого типа сделать "Horse, Pig, Cat, Dog, Cow". Тогда переменная типа Animals сможет принять значение Animals.Horse или, к примеру, Animals.Cat.
Ниже приведу значения для типов DayType и TimeType.
Для справки: Перечислимый тип - это тип данных, переменные которого могут принимать значения заранее заданные пользователем. Например, можно создать тип "Animals", и возможными значениями у этого типа сделать "Horse, Pig, Cat, Dog, Cow". Тогда переменная типа Animals сможет принять значение Animals.Horse или, к примеру, Animals.Cat.
Ниже приведу значения для типов DayType и TimeType.
- DayType
- Holiday
- NonWorking
- Working
- TimeType
- Work
- NotWork
пятница, 11 февраля 2011 г.
Просмотр структуры карточки.
Иногда возникает потребность просмотреть, какие свойства содержит та, или иная карточка.
Для этого можно воспользоваться утилитой DVExplorer, входящей в SDK.
После запуска утилиты и подключения к базе выбираем пункт "Card Types..."
Для этого можно воспользоваться утилитой DVExplorer, входящей в SDK.
После запуска утилиты и подключения к базе выбираем пункт "Card Types..."
Темы, поднимаемые в сообщении:
карточки,
DVExplorer,
HowTo,
xml
Обращение к карточке Бизнес-календаря. Примерная структура класса.
Ни для кого не секрет, что существует тип карточек "Бизнес-календарь". Они позволяют задать расписание работы, рабочие часы для подразделений и выполняют подобные этим функции.
Для того, чтобы обратиться к конкретной карточке календаря нужно узнать ее Guid. Проще всего это сделать, кликнув на бизнес-календарь правой кнопкой и зайти в свойства. Внизу будет указан URL карточки, он то и будет содержать легко узнаваемый Guid.
Далее в самой карточке нужно сделать следующее:
В результате выполнения будет создан объект класса Calendar, имеющий весьма сложную структуру. Кроме свойств и методов, унаследованных от класса DomainObject, он включает в себя поле DefaultWorkTime типа IList (как я понял, так же представлены столбцы в табличном контроле). DefaultWorkTime содержит соответственно поля StartTime и EndTime, содержащие границы рабочего дня по-умолчанию. Они используются, если в календаре не приписаны рабочие часы, отличающиеся от них.
Если же рабочие часы заданы индивидуально для каждого дня, то нужно будет обращаться к полю Years (IDictionary), содержащему данные о каждом дне (int DayNumber,enum Type(Working,NonWorking,Holiday),IList WorkTime:(StartTime,EndTime)).
Также для работы с календарем может быть полезен класс WorkTimeCalculator, который содержит два метода: GetDayTimeWorkStatus(DateTime date) и GetDayWorkStatus(DayTime date), возвращающие значения типов TimeType и DayType соответственно.
Создать объект класса WorkTimeCalculator можно следующим способом:
Для того, чтобы обратиться к конкретной карточке календаря нужно узнать ее Guid. Проще всего это сделать, кликнув на бизнес-календарь правой кнопкой и зайти в свойства. Внизу будет указан URL карточки, он то и будет содержать легко узнаваемый Guid.
Далее в самой карточке нужно сделать следующее:
using DocsVision.BackOffice.Model.BusinessCalendar.DataAccess; using DocsVision.BackOffice.Model.BusinessCalendar.Entities; /* . . . */ Guid calGuid = new Guid("F827960F-6E61-40AD-A7E4-63AF74FAB54A"); Calendar cal = new CalendarMapper(Session).Find(calGuid);
В результате выполнения будет создан объект класса Calendar, имеющий весьма сложную структуру. Кроме свойств и методов, унаследованных от класса DomainObject, он включает в себя поле DefaultWorkTime типа IList (как я понял, так же представлены столбцы в табличном контроле). DefaultWorkTime содержит соответственно поля StartTime и EndTime, содержащие границы рабочего дня по-умолчанию. Они используются, если в календаре не приписаны рабочие часы, отличающиеся от них.
Если же рабочие часы заданы индивидуально для каждого дня, то нужно будет обращаться к полю Years (IDictionary), содержащему данные о каждом дне (int DayNumber,enum Type(Working,NonWorking,Holiday),IList WorkTime:(StartTime,EndTime)).
Также для работы с календарем может быть полезен класс WorkTimeCalculator, который содержит два метода: GetDayTimeWorkStatus(DateTime date) и GetDayWorkStatus(DayTime date), возвращающие значения типов TimeType и DayType соответственно.
Создать объект класса WorkTimeCalculator можно следующим способом:
using DocsVision.BackOffice.Model.BusinessCalendar; using DocsVision.BackOffice.Model.BusinessCalendar.DataAccess; using DocsVision.BackOffice.Model.BusinessCalendar.Entities; /* . . . */ Calendar cal = new CalendarMapper(Session).Find(new Guid("00000000-0000-0000-0000-000000000000")); WorkTimeCalculator calc = new WorkTimeCalculator(cal);Примечание: вместо 00000000-0000-0000-0000-000000000000 укажите нужный Guid.
Темы, поднимаемые в сообщении:
бизнес-календарь,
скрипт,
C#,
HowTo
среда, 9 февраля 2011 г.
Обращение к данным карточки сотрудника. Программирование действий в ответ на клик по кнопке.
Идея такова: мы выбираем сотрудника в соответствующем контроле типа "сотрудник", затем кликаем по контролу "кнопка", в ответ на что в отдельном свойстве появляется, к примеру, Email или Телефон сотрудника.
Эту задачу можно решить двумя способами:
1 способ (в обход объект-модели):
2 способ (через объект-модель):
Эту задачу можно решить двумя способами:
1 способ (в обход объект-модели):
private void Свойство10_Click(System.Object sender, System.EventArgs e) //Свойство10 - у меня имя кнопки
{
Guid? employeeId=(Guid?)PropertyController.GetPropertyValue("Автор"); //employeeId - ключ на карточку по свойству "Автор". "Автор" - имя контрола типа "сотрудник"
if (employeeId.HasValue) //проверка существования значения ключа employeeId
{
var empl=new DocsVision.BackOffice.Model.StaffModel.DataAccess.EmployeeMapper(Session).Find(employeeId.Value); //новая переменная, в которую записываем значение employeeId.Value
PropertyController.UpdateProperty("Свойство12",empl.Email); //Записываем в свойство типа "строка" значение empl.Email. Соответственно мы можем вытащить в качестве значение не только Email, а практически любое свойство карточки сотрудника
PropertyController.RefreshControls(); //обновляем контролы, чтобы отобразилось новое значение
}
else
{
MessageBox.Show("Ошибка"); //сообщение об ошибке, если employeeId не имеет значения
}
}
2 способ (через объект-модель):
private void Свойство10_Click(System.Object sender, System.EventArgs e)
{
Guid? employeeId=(Guid?)PropertyController.GetPropertyValue("Автор");
if (employeeId.HasValue)
{
RowData employeeData=Session.CardManager.GetDictionaryData(new Guid("6710B92A-E148-4363-8A6F-1AA0EB18936C")).Sections[new Guid("DBC8AE9D-C1D2-4D5E-978B-339D22B32482")].GetRow(employeeId.Value);
//RefStaffCardId = 6710B92A-E148-4363-8A6F-1AA0EB18936C (Правой кнопкой на справочник сотрудников, экспорт, XML карточки)
//Employee = DBC8AE9D-C1D2-4D5E-978B-339D22B32482 (C:\Program Files\DocsVision\Platform\4.5\Server\Tools\Database\TakeOffice\RefStaff.xml - строчка с employee)
PropertyController.UpdateProperty("Свойство12",employeeData["Phone"].ToString()); //Phone - стандартное имя ячейки в базе данных, хранящей значение "Телефон" определенного сотрудника
PropertyController.RefreshControls();
}
else
{
MessageBox.Show("Ошибка");
}
}
Скрипт из мануала.
для того, чтобы при открытии карточки,ей присваивался регистрационный номер автоматически, существует след скрипт:
отыскиваете в событиях карточки событие AfterActivate, жмете три точки и открывается скрипт,первая строка генерится автоматически,а далее копируем скрипт)
отыскиваете в событиях карточки событие AfterActivate, жмете три точки и открывается скрипт,первая строка генерится автоматически,а далее копируем скрипт)
private void cardControl_AfterActivate(System.Object sender, System.EventArgs e) { var numeratorProperty = GetCardProperty("Нумератор"); //здесь в скобках идет настоящее имя вашего регистратора, у меня "нумератор" if (numeratorProperty.Value != null) { return; } var ruleAttribute = numeratorProperty.Description.GetAttribute("Rule"); //обратите внимание,что в этом месте как раз идет НЕ настояшее имя вашего правила для регистратора,а стандартное название Rule Guid? ruleId = (Guid?)ruleAttribute.Value; var numeratorMapper = new DocsVision.BackOffice.Model.CardProperties.DataAccess.NumeratorNumberMapper(Session, CardData.Id, DomainObject.NumbersSectionId.Value); var number = numeratorMapper.Create(ruleId.Value); numeratorProperty.Value = number; PropertyController.RefreshControls(); } private CardProperty GetCardProperty(string propertyName) { foreach (CardProperty property in PropertyController.CardProperties) { if (property.Name == propertyName) return property; } return null; }
Пара багов
При написании скрипта наткнулся на следующую ошибку:
Ошибка
Если на карточке лежит контрол "Время", то, если в него не было принудительно записано какое-то значение через скрипт (значение по-умолчанию не в счет), то при попытке считать значение контрола возвращается объект неправильного типа.
Способ решения
Задавать значения по-умолчанию для этого контрола в событии карточки CardInitialized.
Ошибка
Если на карточке есть скрытый контрол, то данные о изменении его значения будут также выводиться в истории.
Способ решения
Пока не придуман.
Ошибка
Если на карточке лежит контрол "Время", то, если в него не было принудительно записано какое-то значение через скрипт (значение по-умолчанию не в счет), то при попытке считать значение контрола возвращается объект неправильного типа.
Способ решения
Задавать значения по-умолчанию для этого контрола в событии карточки CardInitialized.
Ошибка
Если на карточке есть скрытый контрол, то данные о изменении его значения будут также выводиться в истории.
Способ решения
Пока не придуман.
Получение типа значения контрола
Часто при считывании значения свойства карточки может возникнуть вопрос о том, какого типа нужно создать переменную для хранения этого значения.
Для того, чтобы узнать тип значения свойства, можно воспользоваться следующим методом:
Для того, чтобы узнать тип значения свойства, можно воспользоваться следующим методом:
MessageBox.Show(PropertyController.GetPropertyValue("ИмяСвойства").GetType().ToString());В результате при выполнении скрипта будет показано окно сообщения с названием типа выбранного свойства.
Темы, поднимаемые в сообщении:
конструктор,
скрипт,
C#,
HowTo,
property
Вступление
Всем привет!
Вот и возник наш блог) Дизайн и структура возможно будут дорабатываться по мере необходимости.
В данный момент оставлять сообщения и комментарии могут только участники блога, получившие приглашения, и у блога отключена индексация в поисковых системах.
Вот и возник наш блог) Дизайн и структура возможно будут дорабатываться по мере необходимости.
В данный момент оставлять сообщения и комментарии могут только участники блога, получившие приглашения, и у блога отключена индексация в поисковых системах.
Подписаться на:
Сообщения (Atom)