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

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 09.03.2021, 11:31   #1  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,391 / 4251 (200) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
Как узнать, что форма открыта через "Перейти к форме основной таблицы"?
ax2009 и другие классические аксапты.

я в методе init добавил вызов метода, который правит query И вызывает executeQuery
сама форма работает хорошо.

но кнопка "Перейти к форме основной таблицы" не позиционируется на нужную запись, а показывает все записи нового запроса.

Как узнать, что форма открыта через "Перейти к форме основной таблицы"?
__________________
Полезное на axForum, GitHub, Facebook, mazzy.priot, mazzy.music, coub.
Старый 09.03.2021, 11:50   #2  
raz is offline
raz
NavAx
Аватар для raz
NavAx Club
Лучший по профессии 2014
Лучший по профессии 2009
 
1,462 / 987 (35) +++++++
Регистрация: 22.07.2003
Адрес: МО
element.args().caller()?
За это сообщение автора поблагодарили: mazzy (2).
Старый 09.03.2021, 12:00   #3  
sukhanchik is offline
sukhanchik
Moderator
Аватар для sukhanchik
MCBMSS
Злыдни
Лучший по профессии 2015
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
2,943 / 2944 (104) +++++++++
Регистрация: 13.06.2004
Адрес: Москва
Цитата:
Сообщение от mazzy Посмотреть сообщение
Как узнать, что форма открыта через "Перейти к форме основной таблицы"?
В общем случае никак. Ведь метод jumpRef перекрыть может каждый разработчик и написать там абсолютно любой код, в т.ч. вызвать форму без указания caller и прочих атрибутов.
Но если говорить про ядро, то есть же методы args,caller(), args.record(), args.lookupField(), args.lookupValue() - которые содержат осмысленные значения. Еще появился метод args.lookupRecord().
Соответственно, можно проанализировать эти методы на наличие заполненных значений и на основе этого сделать вывод о том, что форма была вызвана ядром через "Переход к основной таблице".
__________________
Возможно сделать все. Вопрос времени
За это сообщение автора поблагодарили: mazzy (2).
Старый 09.03.2021, 12:31   #4  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,534 / 2478 (90) +++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Можно еще посмотреть стек вызовов вызовом xSession::xppCallStack()
При обычном открытии там что-то типа

(C)\Forms\MyForm\Methods\init
(C)\Classes\SysSetupFormRun\init

А если переход к основной таблице, то что-то типа такого

(C)\Forms\MyForm\Methods\init
(C)\Classes\SysSetupFormRun\init
(C)\Classes\FormDataObject\jumpRef
(C)\Classes\FormStringControl\jumpRef
(C)\Classes\FormRun\Task
(C)\Classes\SysSetupFormRun\Task
(C)\Classes\FormStringControl\Context
За это сообщение автора поблагодарили: mazzy (2).
Старый 09.03.2021, 12:39   #5  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,391 / 4251 (200) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
Цитата:
Сообщение от raz Посмотреть сообщение
element.args().caller()?
а разве caller заполняется только для jumpRef?
хотя мысль хорошая, а не сломались ли и остальные случаи с заполненным caller. И что это за случаи.

Спасибо. Продуктивная мысль.

Цитата:
Сообщение от Logger Посмотреть сообщение
Можно еще посмотреть стек вызовов вызовом xSession::xppCallStack()
При обычном открытии там что-то типа

(C)\Forms\MyForm\Methods\init
(C)\Classes\SysSetupFormRun\init

А если переход к основной таблице, то что-то типа такого

(C)\Forms\MyForm\Methods\init
(C)\Classes\SysSetupFormRun\init
(C)\Classes\FormDataObject\jumpRef
(C)\Classes\FormStringControl\jumpRef
(C)\Classes\FormRun\Task
(C)\Classes\SysSetupFormRun\Task
(C)\Classes\FormStringControl\Context
угу. я думал об этом. но такой способ мне категорически не нравится - SysSetupFormRun может быть правлен. Диггером, например. или TaskRecorder'ом. Или еще чем аналогичным
__________________
Полезное на axForum, GitHub, Facebook, mazzy.priot, mazzy.music, coub.
Старый 09.03.2021, 12:42   #6  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,534 / 2478 (90) +++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Цитата:
Сообщение от mazzy Посмотреть сообщение
угу. я думал об этом. но такой способ мне категорически не нравится - SysSetupFormRun может быть правлен. Диггером, например. или TaskRecorder'ом. Или еще чем аналогичным
Мне он тоже не очень нравится, но если ничего лучше не придумают, то думаю что можно. Опять же можно закладываться не на весь стек вызовов, а, например, поискать в глубину на 2-4 метода, есть ли в стеке метод с именем JumpRef и все. Тогда наследник SysSetupFormRun не повлияет.
За это сообщение автора поблагодарили: mazzy (2).
Старый 09.03.2021, 12:43   #7  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,391 / 4251 (200) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
Цитата:
Сообщение от mazzy Посмотреть сообщение
Как узнать, что форма открыта через "Перейти к форме основной таблицы"?
может быть, тогда стоит переформулировать вопрос:

я должен модифицировать запрос на форме - включить/выключить childDatasource с existJoin, изменить Range в зависимости от переключателя на форме, который переключает пользователь (вот хотят они. причем обосновано)

как лучше это сделать так, чтобы не сломать остальную функциональность аксапты?
__________________
Полезное на axForum, GitHub, Facebook, mazzy.priot, mazzy.music, coub.
Старый 09.03.2021, 13:22   #8  
sukhanchik is offline
sukhanchik
Moderator
Аватар для sukhanchik
MCBMSS
Злыдни
Лучший по профессии 2015
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
2,943 / 2944 (104) +++++++++
Регистрация: 13.06.2004
Адрес: Москва
Цитата:
Сообщение от mazzy Посмотреть сообщение
как лучше это сделать так, чтобы не сломать остальную функциональность аксапты?
Поделюсь опытом, как это делал я.
Вариант 1. Стандартная форма, нестандартный вызов. Например, вызываем форму InventTrans из своей формы, в которой есть строки с номенклатурами. В этом случае в своей форме в методе jumRef пишем что-то типа
X++:
    Args                 args;
    Query                query;
    QueryBuildDataSource qbds;
    ;
    query = new Query();
    qbds = query.addDataSource(tableNum(InventTransOrigin));
    qbds.addRange(fieldNum(InventTransOrigin, InventTransId)).value(queryValue(_inventTransId));
    args = new Args();
    args.initialQuery(InitialQueryParameter::createByQuery(query));
    MenuFunction::runClient(menuitemDisplayStr(InventTrans), MenuItemType::Display, true, args);
Класс InitialQueryParameter появился в АХ с тех пор, как появилось Избранное и стало возможно в избранном менять запрос. Т.е. с 4.0

Для некоторых случаев есть уже готовые методы типа
X++:
InventJournalFormTable::jumpRefReferenceId(inventJournalTable.JournalId);
Еще есть вариант (если нужно чего-то сделать с датасорсами) - написать код по аналогии с формой SysTableBrowser, там достучаться до датасорса и уже с ним чего-то делать

Вариант 2. Стандартная / малоизмененная форма, свой вызов. Добавили новое поле в форму CustTable и хотим по нему сделать свой переход. Тогда есть 2 решения - либо как в Варианте 1, либо на init формы / датасорса уже открываемой формы анализировать методы класса Args: caller / lookupField / record / lookupValue, которые уж несложно заполнить из jumpRef-а вызываемой формы
__________________
Возможно сделать все. Вопрос времени

Последний раз редактировалось sukhanchik; 09.03.2021 в 13:52.
Старый 09.03.2021, 14:22   #9  
DSPIC is offline
DSPIC
Боец
Аватар для DSPIC
MCP
Лучший по профессии 2017
Лучший по профессии 2014
Лучший по профессии 2009
 
1,052 / 1114 (40) ++++++++
Регистрация: 11.04.2008
Адрес: Минск
X++:
public void init()
{
    super();
    
    info(strFmt("%1 %2 %3", element.args().lookupTable(), element.args().lookupField(),  element.args().lookupValue()));
}
Если в этих методах что-то валяется, то очень вероятно это был JumpRef.
__________________
Мой блог
За это сообщение автора поблагодарили: mazzy (2).
Старый 09.03.2021, 14:39   #10  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,391 / 4251 (200) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
element.args().caller() - хорошая мысль. но очень грубо
element.args().lookup*() - прекрасно. спасибо.

но я пошел уже другим путем и отрефакторил.
принцип по которому я пошел:
  1. я не добавляю свой датасорса в форму. что делает модификацию сильно легче - один edit-метод на форме + 1 контрол на форме
  2. я использую тот факт, что после super() в инициализации есть только Query, а QueryRun == null
  3. я работаю только с queryrun().query(), использую research(). И никогда сам не вызываю executeQuery(), который пересоздает queryRun из АОТ
  4. в частности, я добавляю свой датасорс только после того, как пользователь выбрал какой-то пункт в переключателе
  5. я отрефакторил код и трактую отсутствие моего датасорса как вполне валидное состояние "Все записи"

получился вот такой код:

X++:
protected static MdmViewMode get(FormDataSource fdsMain, TableId shadowTableId)
{
    MdmViewMode             ret;

    EnumId                  enumId      = enumnum(MdmType);
    QueryRun                qr          = fdsMain ? fdsMain.queryRun() : null;
    QueryBuildDataSource    qbds        = qr      ? qr.query().dataSourceTable(shadowTableId, 1) : null;
    SysDictField            field       = qbds    ? SysDictTable::fieldWithEnum(qbds.table(), enumId) : null;
    QueryBuildRange         qbr         = field   ? qbds.findRange(field.id()) : null;
    str                     rangeValue  = qbr     ? qbr.value() : '';
    ;

    if( !qbds || !qbds.enabled() )
    {
        ret = MdmViewMode::All;
    }
    else if( qbds && qbds.joinMode() == JoinMode::NoExistsJoin && rangeValue == SysQuery::value(MdmEnumViewMode::completed()) )
    {
        ret = MdmViewMode::InProcess;
    }
    else if( qbds && qbds.joinMode() == JoinMode::NoExistsJoin && rangeValue == SysQuery::value(MdmType::StopProcessing) )
    {
        ret = MdmViewMode::Active;
    }
    else if( qbds && qbds.joinMode() == JoinMode::ExistsJoin && rangeValue == SysQuery::value(MdmType::StopProcessing) )
    {
        ret = MdmViewMode::Stopped;
    }
    else if( qbds && qbds.joinMode() == JoinMode::ExistsJoin && rangeValue == SysQuery::value(MdmType::Error) )
    {
        ret = MdmViewMode::Error;
    }
    else
    {
        ret = MdmViewMode::UserDefined;
    }

    return ret;
}
X++:
// предполагаем, что в запросе только один range по полю mdmType
protected static boolean set(
    FormDataSource  fdsMain,
    TableId         shadowTableId,
    MdmViewMode     viewMode)
{
    EnumId                  enumId      = enumnum(MdmType);
    QueryRun                qr          = fdsMain ? fdsMain.queryRun() : null;
    QueryBuildDataSource    qbds        = qr      ? SysQuery::findOrCreateDataSource(qr.query(), shadowTableId, fdsMain.table()) : null;
    SysDictField            field       = qbds    ? SysDictTable::fieldWithEnum(qbds.table(), enumId) : null;
    str                     rangeValue;
    ;

    if( qbds && field )
    {
        startLengthyOperation();

        switch( viewMode )
        {
            case MdmViewMode::UserDefined:
                qbds.enabled(true);
                qbds.relations(true);
                qbds.joinMode(JoinMode::InnerJoin);
                rangeValue = SysQuery::valueUnlimited();
                break;

            case MdmViewMode::All:
                qbds.enabled(false);
                qbds.relations(true);
                qbds.joinMode(JoinMode::ExistsJoin);
                rangeValue = SysQuery::valueUnlimited();
                break;

            case MdmViewMode::InProcess:
                qbds.enabled(true);
                qbds.relations(true);
                qbds.joinMode(JoinMode::NoExistsJoin);
                rangeValue = SysQuery::value(MdmEnumViewMode::completed());
                break;

            case MdmViewMode::Active:
                qbds.enabled(true);
                qbds.relations(true);
                qbds.joinMode(JoinMode::NoExistsJoin);
                rangeValue = SysQuery::value(MdmType::StopProcessing);
                break;

            case MdmViewMode::Stopped:
                qbds.enabled(true);
                qbds.relations(true);
                qbds.joinMode(JoinMode::ExistsJoin);
                rangeValue = SysQuery::value(MdmType::StopProcessing);
                break;

            case MdmViewMode::Error:
                qbds.enabled(true);
                qbds.relations(true);
                qbds.joinMode(JoinMode::ExistsJoin);
                rangeValue = SysQuery::value(MdmType::Error);
                break;

            default:
                throw error(Error::unsupportedEnum(funcname(), viewMode));
        }

        qbds.fetchMode(QueryFetchMode::One2One);
        qbds.firstOnly(true);

        SysQuery::findOrCreateRange(qbds, field.id()).value(rangeValue);

        fdsMain.research();

        endLengthyOperation();
        return true;
    }

    return false;
}
таким образом я совсем не вмешиваюсь в работу формы до тех пор, пока пользователь не жамкнет переключатель. после того, как жамкнет, в queryrun формы будет добавлен датасорс.

до жамка:
Название: before.PNG
Просмотров: 451

Размер: 7.8 Кб

после жамка:
Нажмите на изображение для увеличения
Название: after.PNG
Просмотров: 368
Размер:	14.6 Кб
ID:	13131

спасибо за советы и помощь.
__________________
Полезное на axForum, GitHub, Facebook, mazzy.priot, mazzy.music, coub.
За это сообщение автора поблагодарили: sukhanchik (2), Raven Melancholic (2).
Старый 10.03.2021, 07:09   #11  
Raven Melancholic is offline
Raven Melancholic
Участник
Аватар для Raven Melancholic
Самостоятельные клиенты AX
Лучший по профессии 2015
 
2,003 / 1103 (41) ++++++++
Регистрация: 21.03.2005
Адрес: Москва-Петушки
А смена типа соединения отрабатывает? Вроде бы раньше не работало.
Имею ввиду вот это:
X++:
qbds.joinMode(JoinMode::InnerJoin);
Понятно, что при первом использовании
X++:
SysQuery::findOrCreateDataSource(...)
то есть, когда сработает часть Create, то установка типа соединения будет работать.
А вот последующие вызовы, когда ужа работает часть Find насколько помню, не работали - на существующем датасорсе не удавалось сменить тип связи.
Старый 10.03.2021, 07:41   #12  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,391 / 4251 (200) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
Цитата:
Сообщение от Raven Melancholic Посмотреть сообщение
А смена типа соединения отрабатывает? Вроде бы раньше не работало.
хороший вопрос. судя по поведению - работает. ax2009, ax2012
а вот как оно там внутре... надо посмотреть.
__________________
Полезное на axForum, GitHub, Facebook, mazzy.priot, mazzy.music, coub.
Старый 10.03.2021, 11:11   #13  
Logger is offline
Logger
Участник
Лучший по профессии 2015
Лучший по профессии 2014
 
3,534 / 2478 (90) +++++++++
Регистрация: 12.10.2004
Адрес: Москва
Записей в блоге: 2
Цитата:
Сообщение от mazzy Посмотреть сообщение
а вот как оно там внутре...
а внутре у ней неонка ...
За это сообщение автора поблагодарили: mazzy (2).
Старый 10.03.2021, 11:11   #14  
TasmanianDevil is offline
TasmanianDevil
Мрачный тип
Аватар для TasmanianDevil
Злыдни
 
871 / 377 (14) ++++++
Регистрация: 24.01.2005
Адрес: Томск
Цитата:
Сообщение от mazzy Посмотреть сообщение
никогда сам не вызываю executeQuery(), который пересоздает
queryRun из АОТ
Я таки уже и дико извиняюсь, что влезаю в дискуссию, но оно не из AOT, а из текущего экземпляра query() источника данных текущего экземпляра формы создается с учетом уже сделанных ранее на этом query() изменений - в противном случае тупо не работали бы фильтры (которые делают через query() источника данных, как например фильтры по разнесенности,неразнесенности в журнальном фреймворке)
К томе же реализация фильтров через queryRun().query() - не самый лучший вариант.
Кто мешает пользователю в такой форме поиграться с запросом и вызвать стандартными средствами executeQuery(), похоронив все созданное непосильным трудом в queryRun().query() ?
__________________
Мы летаем, кружимся, нагоняем ужасы ...

Последний раз редактировалось TasmanianDevil; 10.03.2021 в 11:15.
Старый 10.03.2021, 11:22   #15  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,391 / 4251 (200) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
Цитата:
Сообщение от TasmanianDevil Посмотреть сообщение
Я таки уже и дико извиняюсь, что влезаю в дискуссию, но оно не из AOT, а из текущего экземпляра query() источника данных
угу. я там вообще коряво сформулировал. но править уже нет желаения.

Цитата:
Сообщение от TasmanianDevil Посмотреть сообщение
К томе же реализация фильтров через queryRun().query() - не самый лучший вариант.
Кто мешает пользователю в такой форме поиграться с запросом и вызвать стандартными средствами executeQuery(), похоронив все созданное непосильным трудом в queryRun().query() ?
Именно! никто не мешает пользователю поиграться. В том числе и я не мешаю.

если пользователь "сломает" мои фильтры,
то метод get вернет MdmViewMode::UserDefined
для моего кода это вполне штатная ситуация.

Именно с queryRun!
Это самый лучший вариант.
__________________
Полезное на axForum, GitHub, Facebook, mazzy.priot, mazzy.music, coub.

Последний раз редактировалось mazzy; 10.03.2021 в 11:25.
Старый 13.09.2021, 10:16   #16  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,391 / 4251 (200) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
Цитата:
Сообщение от mazzy Посмотреть сообщение
Как узнать, что форма открыта через "Перейти к форме основной таблицы"?
args.refField()
__________________
Полезное на axForum, GitHub, Facebook, mazzy.priot, mazzy.music, coub.
За это сообщение автора поблагодарили: sukhanchik (3), Ace of Database (3), Logger (3).
 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
Фильтрование записей при "переходе к основной таблице" demID DAX: Программирование 10 18.11.2015 12:52
Баг на форме "Проводки по сопоставлению" S.Kuskov DAX: Программирование 12 29.04.2009 19:19
Через map узнать fieldId Dron AKA andy DAX: Программирование 6 20.02.2004 18:18
Объединить несколько полей таблицы в одном поле Grid-а на форме? storer DAX: Программирование 2 12.11.2003 14:08
"Пустое" значение Enum в веб-форме LedgerVoucher DAX: Программирование 4 25.07.2002 12:35
Опции темы Поиск в этой теме
Поиск в этой теме:

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

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

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

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