AXForum  
Вернуться   AXForum > Microsoft Dynamics AX > DAX Blogs
All
Забыли пароль?
Зарегистрироваться Правила Справка Пользователи Сообщения за день Поиск

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 27.06.2008, 16:03   #1  
belugin is offline
belugin
Участник
Аватар для belugin
Сотрудники Microsoft Dynamics
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии 2011
Лучший по профессии 2009
 
4,622 / 2925 (107) +++++++++
Регистрация: 16.01.2004
Записей в блоге: 5
Мой воариант:
1. Испотьзуюя табакс копируем имена полей в буыер обмена
2. Испоььзуя поиск и замену с регекспами меняем ^(.*)$ на table.$1 = control$2,value() или как-то так
Старый 14.08.2008, 16:59   #2  
Gustav is offline
Gustav
Moderator
Аватар для Gustav
SAP
Лучший по профессии 2009
 
1,858 / 1152 (42) ++++++++
Регистрация: 24.01.2006
Адрес: Санкт-Петербург
Записей в блоге: 19
Автонумерация полей при обмене значениями с записеподобными структурами
Вначале я хотел назвать заметку "Автонумерация колонок при выводе в Excel", так как подобные примеры - наиболее "на слуху", но по ходу сочинения текста появилось более общее название (хотя и менее ясное с первого взгляда).

Итак, о чем же речь? Наверняка многим, как и мне, приходилось писать код, подобный следующему:

X++:
SysExcelCells cells;
;

cells.item( row,  1).value( ledgerTrans.RecId       );
cells.item( row,  2).value( ledgerTrans.AccountNum  );
cells.item( row,  3).value( ledgerTable.AccountName );
.....................................................
cells.item( row,  8).value( ledgerTrans.Txt         );
cells.item( row,  9).value( ledgerTrans.AmountMST   );
cells.item( row, 10).value( ledgerTrans.Crediting   );
т.е. формировать (или читать) некоторую "запись", последовательно нумеруя ее поля жёсткими литералами (см. выше второй параметр метода item). Наиболее частый случай - нумерация колонок при выводе в Excel (самыми разнообразными способами). Кроме вывода в Excel это может быть, например, заполнение значениями массива (класса Array): array.value(1, ...); array.value(2, ...); и т.д. В качестве примера чтения можно привести обращение к полям записи, выбранной из ODBC-источника: ... = resultSet.getString(1).

В принципе, нам совсем не в тягость пронумеровать такие строки вручную, когда речь идет о 10 строчках (нумерация от 1 до 10). В случае сотни строк - ситуация посложнее, но все равно преодолимая. Если неохота разминать пальцы, набивая значения от 1 до 100, то можно обратиться за помощью к Excel и сгенерировать там строчки кода при помощи формулы, имея в одной колонке номер (ячейка A1: 1), в другой значения для value (B1: ledgerTrans.RecId), а в третьей - собственно формулу (C1: ="cells.item(row," & A1 & ").value(" & B1 & ");").

Неприятности начинаются, когда обнаруживается, что в уже написанный код необходимо добавить еще одну "номерную" строку в начало (середину) или поменять строки местами. Особенно "ужасна" ситуация с началом, когда требуется перебивание всех имеющихся номеров: 1 надо перебить на 2, 2 - на 3, 3 - на 4 и т.д.

И вот в один прекрасный день, копаясь в коде от нашего поставщика решения - компании GMCS, я обнаружил в схожей ситуации вывода в Excel милейшее решение проблемы. Из серии тех, до которых сам никогда не додумаешься просто потому, что никогда не задумаешься, пока не увидишь у другого.

Маленькое лирическое отступление. Мне рассказали историю про человека, который частенько оставался у знакомых в гостях на ночь и неудобно спал на маленьком диване, свернувшись калачиком. Через год он (и хозяева!) случайно узнали, что диван, оказывается, раскладной...

Увидев этот код, я испытал примерно такое же ощущение "через год"
X++:
SysExcelCells cells;
int currNum = 0;

int nextNum()
{
   currNum++;
   return currNum;
}
;

cells.item( row, nextNum() ).value( ledgerTrans.RecId       );
cells.item( row, nextNum() ).value( ledgerTrans.AccountNum  );
cells.item( row, nextNum() ).value( ledgerTable.AccountName );
.............................................................
cells.item( row, nextNum() ).value( ledgerTrans.Txt         );
cells.item( row, nextNum() ).value( ledgerTrans.AmountMST   );
cells.item( row, nextNum() ).value( ledgerTrans.Crediting)  );
Понятно, что при таком подходе можно в любой момент безболезненно переставлять строки по желанию или иной необходимости.

Хотел было здесь остановиться, да вспомнил о еще одной "тягомотине". Это уже точно только для Excel и только для тех ситуаций, когда разработчик предпочитает работать с буквенными обозначениями ячеек. При использовании класса ComExcelDocument_RU решение по аналогии c nextNum может выглядеть как-то вот так:
X++:
static void test_nextCell(Args _args)
{
    ComExcelDocument_RU doc = new ComExcelDocument_RU();
    int currCol = 0;
    int currRow = 1;

    str nextCell()
    {
        currCol++;
        return ComExcelDocument_RU::numToNameCell(currCol, currRow);
    }
    ;

    doc.NewFile();
/*
    doc.InsertValue('A1', 10);
    doc.InsertValue('B1', 20);
    doc.InsertValue('C1', 30);
    doc.InsertValue('D1', 40);
*/
    doc.InsertValue( nextCell(), 10);
    doc.InsertValue( nextCell(), 20);
    doc.InsertValue( nextCell(), 30);
    doc.InsertValue( nextCell(), 40);

    doc.finalize();
}
Хотя, конечно, следует признать, что и без того небыстрый класс здесь будет отвлекаться на довольно затратные дополнительные вычисления nextCell. Но если на минуту предположить, что при перестановке строк надо будет перебивать уже не цифры, а буквы, то поневоле согласишься с этими затратами

P.S. 04.03.09. Иногда бывает нужно нумеровать поля несколько раз внутри метода (например, первый раз при создании структуры, а затем при записи в нее). В этом случае нужно позаботиться о своевременном обнулении счетчика (currNum = 0) при повторном проходе по полям структуры.

Чтобы не выносить обнуление в отдельный оператор, можно несколько усовершенствовать функцию nextNum, добавив необязательный параметр "начать с". В этом случае в первой строке, где используется nextNum, нужно будет явно указать стартовый номер (обычно это 1), а в последующих строках применять nextNum без параметров:
X++:
SysExcelCells cells;
int currNum = 0;

int nextNum(int _beginFrom = 0)
{
    if (prmIsDefault(_beginFrom))
        currNum++;
    else
        currNum = _beginFrom;

    return currNum;
}
;

cells.item( row, nextNum(1)).value( ledgerTrans.RecId       );
cells.item( row, nextNum() ).value( ledgerTrans.AccountNum  );
cells.item( row, nextNum() ).value( ledgerTable.AccountName );
В качестве небольшого бонуса - появившаяся возможность нумеровать строки с пропуском. Например, если надо вначале пройтись по полям с 1 по 3, а затем с 9 по 11, то имеем примерно следующее:
X++:
cells.item( row, nextNum(1))...
cells.item( row, nextNum() )...
cells.item( row, nextNum() )...

cells.item( row, nextNum(9))...
cells.item( row, nextNum() )...
cells.item( row, nextNum() )...

Последний раз редактировалось Gustav; 04.03.2009 в 17:58. Причина: добавление
Старый 08.09.2008, 18:39   #3  
Gustav is offline
Gustav
Moderator
Аватар для Gustav
SAP
Лучший по профессии 2009
 
1,858 / 1152 (42) ++++++++
Регистрация: 24.01.2006
Адрес: Санкт-Петербург
Записей в блоге: 19
Изготовление связанных тестовых копий форм журналов и форм строк журналов
У нас в компании две развернутые Аксапты - рабочая и тестовая. Как, наверное, у многих, собственные доработки создаются на тестовой инсталляции и после успешной отладки портируются на рабочее приложение.

Иногда возникает необходимость в экспериментальных "необратимых кромсаниях" какого-нибудь объекта, например, формы. "Необратимых" в данном случае означает, что по окончании эксперимента объект не будет восстановлен к первоначальному виду и будет "полностью удален из системы" (т.е. "наигрались и подчистили за собой"). Такие эксперименты, как правило, проводятся на тестовой базе, являя собой этакое "тестирование в квадрате". Впрочем, в случае крайней необходимости их можно аккуратно проводить и на рабочей, и тогда всё сказанное ниже приобретает дополнительную значимость.

Для целей создания подобных объектов в АОТ существует замечательная контекстная команда "Дублировать". После ее выполнения создается копия объекта под названием "CopyOf<НазваниеИсходногоОбъекта>". Я обычно переношу префикс в конец "<НазваниеИсходногоОбъекта>_CopyOf" и объединяю копии объектов в проект (типа "AllCopyOfs", чтобы потом легко было удалять их всех сразу).

Недавно мне пришлось таким "необратимым" образом экспериментировать с формой InventJournalTable ("Складские журналы"). Быстро был создан клон InventJournalTable_CopyOf. Однако нажатие на кнопку "Строки" приводило к открытию формы, конечно же, не "<CтрокиЖурнала>_CopyOf".

В зависимости от типа складского журнала, запись которого активна в данный момент в гриде формы InventJournalTable, по нажатию кнопки "Строки" открывается соответствующая форма. Меня интересовали журналы переноса, для отображения строк которых используется форма InventJournalTransfer (о чем я и прочитал в поле "Название формы" после щелчка по пункту контекстного меню "Настройка").

Дублированием был создан клон и этой формы - InventJournalTransfer_CopyOf. Но наивно было бы полагать, что при нажатии на "Строки" откроется именно она. Конечно, этого не случилось - "Настройка" по-прежнему показывала "InventJournalTransfer" безо всяких "CopyOf".

Представляя, где нужно еще "подкрутить", я бодро "зашагал" в design формы журнала InventJournalTable_CopyOf и нашёл соответствующую кнопку MenuItemButton: lines. Свойство кнопки "MenuItemName" гласило: InventJournalTransLossProfit (MenuItemType = Display). Быстро найдя с помощью панели Sidax указанный пункт меню, я прочитал в свойствах: Class = Form, Object = InventJournalLossProfit (т.е. никак не нужный мне InventJournalTransfer). Цепь замкнулась, моста не было...

Долго дебажить код я не стал, но в процессе понял, что на досуге надо поизучать классы JournalFormTable и InventJournalFormTable. В них срабатывает логика, которая к моменту щелчка по кнопке "Строки" подставляет в свойство "MenuItemName" нужный в данный момент пункт меню, запускающий нужную форму. Сохраненный в форме InventJournalTable дефолтный пункт меню InventJournalTransLossProfit ни на что не влияет (всё получается и с пустым значением свойства MenuItemName) и лишь сбивает с толку.

Как в итоге далее я добился необходимого мне поведения задействованных объектов:
1. Прочитал пункт меню кнопки lines, перекрыв для нее метод clicked (в форме InventJournalTable_CopyOf):
X++:
void clicked()
{;
    box::info(this.menuItemName()); // InventJournalTransTransfer
    super();
}
2. Создал копию выявленного пункта меню: InventJournalTransTransfer_CopyOf.
3. Создал копию формы, которую прочитал в свойствах этого пункта меню: InventJournalTransfer_CopyOf.
4. Прописал копию формы в копию пункта меню.
5. Окончательно придал методу clicked следующий "обманный" вид:
X++:
void clicked()
{
    this.menuItemName('InventJournalTransTransfer_CopyOf');
    super();
}
Теги
excel, rls, полезное, blog, axapta

 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
dax-lessons: Generate XML Documentation Files for a project - DAX 2009 Blog bot DAX Blogs 0 08.08.2008 19:06
dax-lessons: Active directory in Axapta Blog bot DAX Blogs 0 27.08.2007 23:00
Kashperuk Ivan: AxPaint - make your DAX look cool :) Blog bot DAX Blogs 0 26.06.2007 21:00
Kashperuk Ivan: (DAX 3.0) SysExportDialog form extension Blog bot DAX Blogs 1 15.05.2007 19:16
Kashperuk Ivan: Two very useful projects for DAX Blog bot DAX Blogs 0 20.04.2007 01:14

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход

Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 09:12.
Powered by vBulletin® v3.8.5. Перевод: zCarot
Контактная информация, Реклама.