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

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 12.08.2010, 08:17   #1  
ziva is offline
ziva
Иван Захаров
Злыдни
Лучший по профессии AXAWARD 2013
 
65 / 106 (4) +++++
Регистрация: 25.03.2005
Расширенные возможности отслеживания событий на диалогах классов-наследников RunBase
В AX2009 RU5 появилась возможность простого расширения возможностей отслеживания событий на диалогах классов-наследников RunBase.
Поясню как это использовать (на примере InventBaileeCreateCalc_RU):

1. Добавляем в classDeclaration следующую конструкцию:
X++:
    CustAccount         custAccount;
    DialogField         dialogCustAccount;
    #define.dialogCustAccount('dialogCustAccount')
Здесь мы вынуждены иметь hardcoded название будущего контрола на форме, но дальше мы увидим как красиво это играет.

2. В метод dialog() добавляем вызов ещё пары методов:

X++:
   ...

    dialog.customFieldName_RU(#dialogCustAccount);
    // здесь насильно устанавливаем название создаваемого контрола в форме диалога
    dialogCustAccount = dialog.addFieldValue(typeid(CustAccount), custAccount);

    ...

    dialog.allowControlMethodOverload_RU(true);
    // а теперь разрешаем инстансу настоящего класса отлавливать события контролов

3. Теперь создаём метод dialogCustAccount_modified(), который позволяет отлавливать события контрола с названием 'dialogCustAccount' (если бы мы не изменяли название контрола, то метод бы назвался Fld1_modified, или Fld3_2 - взависимости от того где и как вы вызываете dialog.addField или dialog.addFieldValue)

Примечание: Поля-массивы (Dimension) будут иметь наименование с суффиксом содержащим номер элемента массива. Пример: dialogDimension_1, dialogDimension_2, ...

Очень важное примечание: поскольку в этом методе вы имеете дело с серверной версией класса Dialog, то для корректной работы нужно не забывать обновлять значения полей "обрамляющим" вызовом методов updateServer() и updateClient())

X++:
protected boolean dialogCustAccount_modified()
{
    boolean ret = dialog.curFormControl_RU().modified();
    ;
    dialog.dialogOnClient_RU().updateServer();

    dialogContractCode.value('');
    dialogContractAccount.value('');

    this.dialogActivateFields();

    dialog.updateClient(dialog.dialogOnClient_RU());

    return ret;
}
Вот собственно и всё!
Таким же точно образом можно отслеживать методы lookup(), validate(), selectionChange() и др...

P.S.
Собственно изначально делал это в AX3, а теперь удалось получить это в рамках RU5. Пользуйтесь на здоровье!
За это сообщение автора поблагодарили: db (3), sukhanchik (5), gefr (1), konopello (2), MikeR (1), gl00mie (3), alex55 (1), jeky (1), imir (1).
Старый 12.08.2010, 09:23   #2  
lev is offline
lev
Ищущий знания...
Аватар для lev
Oracle
MCBMSS
Axapta Retail User
 
1,723 / 491 (20) +++++++
Регистрация: 18.01.2005
Адрес: Москва
в аксапте 3.0 отлавливание событий на диалоге сильно глючило, т.е. если на диалоге есть query, то при нажатии кнопки выбор, а потом закрытии её, поля запроса удваивались, если пользователь нажимал раза три кнопку выбор, то форма не умещалась на экран

Вопрос в Ax2009 RU5 это исправили??
__________________
"Страх перед возможностью ошибки не должен отвращать нас от поисков истины." (с)
С Уважением,
Елизаров Артем
Старый 12.08.2010, 09:32   #3  
MikeR is offline
MikeR
MCT
Аватар для MikeR
MCBMSS
Лучший по профессии 2015
Лучший по профессии 2014
 
1,628 / 627 (24) +++++++
Регистрация: 28.11.2005
Адрес: просто землянин
Можно наверное добавить еще и пересчет других полей диалога в зависимости от измененеия в поле. Но честно когда увидел сильно кастомизированный dialog, то переделал все на вызов формочки. Уж больно гиморно поддерживать
__________________
Axapta book for developer
Старый 12.08.2010, 10:56   #4  
titov is offline
titov
Участник
 
73 / 87 (3) ++++
Регистрация: 23.12.2005
Адрес: Казань
dialog.customFieldName_RU(#dialogCustAccount);
dialogCustAccount = dialog.addFieldValue(typeid(CustAccount), custAccount);
dialogItemId = dialog.addFieldValue(typeid(ItemId), ItemId);

вопрос - какое имя контрола после выполнения третьей строки кода?

ps нет под рукой ax2009 RU5
Старый 12.08.2010, 11:34   #5  
ice is offline
ice
Участник
Аватар для ice
Лучший по профессии 2014
 
1,689 / 405 (17) +++++++
Регистрация: 23.03.2006
Цитата:
Сообщение от titov Посмотреть сообщение
dialog.customFieldName_RU(#dialogCustAccount);
dialogCustAccount = dialog.addFieldValue(typeid(CustAccount), custAccount);
dialogItemId = dialog.addFieldValue(typeid(ItemId), ItemId);

вопрос - какое имя контрола после выполнения третьей строки кода?

ps нет под рукой ax2009 RU5
после создания поля dialogCustAccount, переменная, содержащая название нового поля, обнуляется
Старый 30.08.2011, 19:32   #6  
jeky is offline
jeky
:o)
Аватар для jeky
 
130 / 64 (3) ++++
Регистрация: 22.05.2008
?
доброго !
подскажите, пожалуйста, как правильно вызвать lookup в данном контексте
Вложения
Тип файла: xpo FD0230_KM00102_ProdTableBOMIdUpd_Jeky_KOM_DEV_300811.xpo (179.3 Кб, 322 просмотров)
__________________
"Только на Бога не может быть обиды - если смерть пошлет, значит, жизни пришел предел, на то рождался,- а за все остальное на Земле есть и должен быть спрос!." Чингиз Торекулович Айтматов.

Последний раз редактировалось jeky; 30.08.2011 в 20:06.
Старый 30.08.2011, 20:20   #7  
jeky is offline
jeky
:o)
Аватар для jeky
 
130 / 64 (3) ++++
Регистрация: 22.05.2008
Thumbs up
Спасибо всем и Wamr-у
Покопалась в классе InventBaileeCreateCalc_RU - всё получилось!!
__________________
"Только на Бога не может быть обиды - если смерть пошлет, значит, жизни пришел предел, на то рождался,- а за все остальное на Земле есть и должен быть спрос!." Чингиз Торекулович Айтматов.
За это сообщение автора поблагодарили: gefr (1).
Старый 02.09.2011, 11:50   #8  
shogel is offline
shogel
Участник
MCBMSS
Соотечественники
 
132 / 169 (6) ++++++
Регистрация: 21.02.2007
Адрес: Finland
В DAX 2012 можно делать вот так:
X++:
protected void updateDesign() 
{     
     formStringCtrl = form.control(#StringCtrlId);
     formStringCtrl.registerOverrideMethod( 
          methodStr(FormStringControl, JumpRef), 
          methodStr(MyFormHandlerClass, custTableJumpRef), 
          this); 
}  

public void custTableJumpRef(FormStringControl _control) 
{     
     Args args = new Args();     
     args.record(formDS.cursor());     
     new MenuFunction(menuitemdisplaystr(CustTable), MenuItemType::Display).run(args); 
}
__________________
The 50-50-90 rule: Any time you have a 50-50 chance of getting something right, there’s a 90% probability you’ll get it wrong.
За это сообщение автора поблагодарили: alex55 (1).
Старый 12.09.2011, 11:42   #9  
gefr is offline
gefr
Участник
Аватар для gefr
MCBMSS
 
147 / 17 (1) ++
Регистрация: 01.11.2004
Адрес: МО, Котельники
Мне нужно:
1. Выполнять различный лукап в зависимости от значения друго поля. Срослось.

2. Разрешать выбор нескольких значений. Посмотел, как делается на SysQueryForm, сделал, не работает. Заменяет другое значение при повторном выборе:
X++:
protected void dialogAccountRelation_lookup()
{
    SysLookup       sysLookup;
    Query                query=new Query();
    QueryBuildDataSource queryBuildDataSource;
    FormControl _formcontrol=dialog.curFormControl_RU();
    TmpSysQuery TmpSysQuery;
    boolean rn=false;
    ;

oldvalue=_formcontrol.valueStr();
dialog.dialogOnClient_RU().updateServer();
if(this.priceModule(dialogRelation.value())==ModuleInventCustVend::Vend){
    switch(dialogAccountCode.value()){
    case TableGroupAll::All:break;
    case TableGroupAll::GroupId:
        queryBuildDataSource=query.addDataSource(tablenum(VendGroup));
        TmpSysQuery.initValue();
        TmpSysQuery.Table_Id=tablenum(VendGroup);
        TmpSysQuery.Field_Id=fieldnum(VendGroup,VendGroup);
        TmpSysQuery.insert();

        rn=true;
        break;
    case TableGroupAll::Table:
        queryBuildDataSource=query.addDataSource(tablenum(VendTable));
        TmpSysQuery.initValue();
        TmpSysQuery.Table_Id=tablenum(VendTable);
        TmpSysQuery.Field_Id=fieldnum(VendTable,AccountNum);
        TmpSysQuery.insert();
        rn=true;
        break;
    }
    if(rn){
        syslookup::lookupRange(_formcontrol,TmpSysQuery,query);
        dialog.updateClient(dialog.dialogOnClient_RU());
        }
 } else info("Поддерживается только для модуля поставщиков");
Переделал midified, чтобы отработать ситуацию. В нем оказалось, что старое значение сохраняется в это методе:
X++:
protected void dialogAccountRelation_modified(){
 ;
 dialog.dialogOnClient_RU().updateServer();
 if(OldValue) dialogAccountRelation.value(OldValue+dialogAccountRelation.value());
 dialog.updateClient(dialog.dialogOnClient_RU());
 }
Т.е. выбирал в первый раз 001, поставил "|", сделал повторный лукап, выбрал 002, на выходе в значении поля - не "001|002", как ожидалось, а "001|001|"
Не подскажете, где косяк?
Старый 12.09.2011, 12:58   #10  
gefr is offline
gefr
Участник
Аватар для gefr
MCBMSS
 
147 / 17 (1) ++
Регистрация: 01.11.2004
Адрес: МО, Котельники
Все, разобрался сам. В Лукапе не нужен был super(), чего-то и в modified тоже его подзабыл поставить
Старый 09.02.2012, 19:27   #11  
gl00mie is offline
gl00mie
Участник
MCBMSS
Most Valuable Professional
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
3,684 / 5788 (200) ++++++++++
Регистрация: 28.11.2005
Адрес: Москва
Записей в блоге: 3
Доработка метода Dialog.customFieldName_RU()
Цитата:
Сообщение от ziva Посмотреть сообщение
Добавляем в classDeclaration следующую конструкцию:
X++:
#define.dialogCustAccount('dialogCustAccount')
Здесь мы вынуждены иметь hardcoded название будущего контрола на форме.
2. В метод dialog() добавляем вызов ещё пары методов:
X++:
// здесь насильно устанавливаем название создаваемого контрола в форме диалога
dialog.customFieldName_RU(#dialogCustAccount);
// ...
3. Теперь создаём метод dialogCustAccount_modified(), который позволяет отлавливать события контрола с названием 'dialogCustAccount'.
Поскольку мне лично не нравятся hardcoded-названия, зависимости которых от названий других сущностей нельзя проверить компилятором, решил немного подрихтовать метод "насильной установки названия контрола", чтобы он мог принимать название метода-перехватчика событий на контроле и по нему "понимал", как надо назвать контрол. За счет этого можно избавиться от лишних макросов и получить дополнительные проверки на этапах компиляции и выполнения.
X++:
/// <summary>
///     позволяет задать название следующего добавляемого в диалог контрола
/// </summary>
/// <param name="_customFieldName">
///     желаемое название контрола ИЛИ название метода объекта, перекрывающего один из методов контрола
/// </param>
/// <param name="_isOverloadedFormCtrlMethodName">
///     если true, то из _customFieldName будет выделено желаемое название контрола, иначе название получится таким, как заказали
/// </param>
/// <remarks>
///     Если _isOverloadedFormCtrlMethodName == true, то из названия контрола вырезается название предположительно перекрытого на нем метода,
///     при этом перебираются все возможные методы контрола, не являющиеся свойствами и не объявленные как final (такие перекрыть нельзя).
///     Т.о. можно передавать сюда название метода объекта, а не просто строку, что обеспечит контроль на этапе компиляции: имена контрола и метода уже не "разъедутся"
/// </remarks>
/// <exception cref="Exception::Error">
///     выбрасывается, если _isOverloadedFormCtrlMethodName == true, но из переданного названия метода не удалось выделить желаемое название контрола
/// </exception>
public final void customFieldName_RU(str _customFieldName, boolean _isOverloadedFormCtrlMethodName = false)
{
    #macrolib.AOT

    DictMethod      dictMethod;
    DictClass       dictClass;
    TreeNodePath    methodPath;
    TreeNode        methodNode;
    str             methodSign;
    str             pattern;
    Counter         n;
    ;
    if (_isOverloadedFormCtrlMethodName && _customFieldName)
    {
        // перебираем все методы класса контрола, которые можно перекрыть, и пытаемся "догадаться", какому методу соответствует название в _customFieldName
        // TODO возможно, следует перебирать методы нескольких объектов, а не только FormStringControl
        dictClass = new DictClass(classnum(FormStringControl));
        for (n = 1; n <= dictClass.objectMethodCnt(); n++)
        {
            dictMethod = new DictMethod(UtilElementType::Class, dictClass.id(), dictClass.objectMethod(n));
            if (    dictMethod
                && !dictMethod.isAbstract()
                && !dictMethod.isStatic()
                && !dictMethod.propertyMethod()
               )
            {
                // дополнительная проверка, что метод - не final, иначе ведь его нельзя перекрыть...
                methodPath = strfmt(#SystemClassesPath + @'\%1\%2', dictClass.name(), dictMethod.name());
                methodNode = TreeNode::findNode(methodPath);
                if (methodNode)
                {
                    methodSign = methodNode.AOTtoolTip();
                    methodNode.treeNodeRelease();
                    methodNode = null;
                    if (!(  match(@'<final ', methodSign)
                        ||  match(@' final ', methodSign)
                       ))
                    {
                        pattern = strfmt(@'<[0-9a-z_]+_%1>', dictMethod.name());
                        if (match(pattern, _customFieldName))
                        {
                            // BINGO!
                            // выделяем из названия метода, перекрывающего метод контрола, желаемое название контрола
                            customFieldName = substr(_customFieldName, 1, strlen(_customFieldName) - strlen(dictMethod.name()) - 1);
                            break;
                        }
                    }
                }
            }
        }
        if (customFieldName == '')
        {
            throw error(strfmt(@"Не удалось определить, какой метод контрола перекрывает метод с названием '%1'", _customFieldName));
        }
    }
    else
        customFieldName = _customFieldName;
}
/*
void customFieldName_RU(str _customFieldName)
{
    ;
    customFieldName = _customFieldName;
}
*/
Пример использования:
X++:
dialog.customFieldName_RU(methodstr(MyClassName, dialogCustAccount_modified), true);
За это сообщение автора поблагодарили: Logger (3), Eldar9x (7), Kiot (1).
Теги
ax2009, dialog, законченный пример, полезное

 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
Протоколирование запуска классов наследников RunBase polygris DAX: Программирование 9 11.02.2010 15:59
Расширенные возможности Query - арифметические операции в условие Where. Lemming DAX: Программирование 10 07.02.2008 14:38
Inside Dynamics AX 4.0: RunBase Framework Extension Part IV Blog bot DAX Blogs 0 02.10.2007 04:49
Inside Dynamics AX 4.0: RunBase Framework Extension Part III Blog bot DAX Blogs 0 02.10.2007 04:49
Inside Dynamics AX 4.0: RunBase Framework Extension Part I Blog bot DAX Blogs 0 30.09.2007 09:20
Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

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

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

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