...feel the spirit of Microsoft Dynamics AX RSS 2.0
 Saturday, October 24, 2009

In Microsoft Dynamics AX beziehen Masken ihre Daten, oder anders gesagt die Daten welche sie anzeigen, über so genannte DataSources.
In einer DataSource sind somit die aktuellen auf der Maske angezeigten Daten (lokal) gespeichert.

Zugriff auf den jeweils aktuell ausgewählten Datensatz erhält man üblicherweise über genau diese DataSource.
Der ausgewählte Datensatz kann unter anderem auch, z.B. durch ein MenuItem(Button), an eine Funktion oder andere Maske übergeben werden.
Hierfür muss nur die Eigenschaft “DataSource”, in diesem Beispiel des MenuItem(Button), entsprechend eingestellt sein.

Ist keine DataSource in den Eigenschaften hinterlegt wird immer die erste DataSource der Query verwendet bzw. dessen aktiver Datensatz übergeben.
In der Regel ist dies die DataSource, welche beim Erstellen der Maske als erstes hinzugefügt oder erstellt wurde (Ausnahme ist hier eine eventuelle Manipulation der Query per Programmcode).

Dieses Vorgehen ist für 90% aller Fälle das wohl am besten geeignete Vorgehen und wird in dieser Weise auch vom Dynamics AX Standard verwendet.
Leider gibt es Anwendungsfälle, bei denen diese “starre Verbindung” von DataSource und z.B. Button oder MenuItem nicht funktioniert, beziehungsweise nicht zum gewünschten Ergebnis führt.

Angenommen man hat eine Maske mit zwei DataSources (CustTable und SalesTable), deren Daten über zwei Grids angezeigt werden, sowie einen Button, welcher eine Operation mit dem zuletzt ausgewählten Datensatz (unabhängig von der DataSource) durchführen soll.
Wenn ein Datensatz der DataSource “CustTable” selektiert wurde, soll dieser verarbeitet werden.
Ist zuletzt ein Datensatz der DataSource “SalesTable” selektiert wurden, soll die Operation mit diesem Datensatz erfolgen.

Maske

Bei dieser Anforderung ergibt sich das Problem, dass die Standardvorgehensweise zur Abfrage des selektierten Datensatzes nicht funktioniert, da hierfür eine der DataSources “direkt” angesprochen werden muss.
Welche DataSource nun aber die “aktive” ist, lässt sich leider nicht ermitteln, da standardmäßig jede DataSource einen “aktiven” Datensatz hat und somit eine Unterscheidung, ob der Aufruf für die “CustTable” oder “SalesTable” erfolgen soll, nicht möglich ist.

Über die Methode “docCursor” der Klasse FormRun bietet sich eine zweite Möglichkeit, den aktiven (ausgewählten) Datensatz zu ermitteln.
Dieses Vorgehen wird z.B. vom Dokumentenmangement (Form “DocuView”) verwendet, um den zuletzt gewählten Datensatz zu ermitteln und somit die dem Datensatz zugeordneten Dokumente anzuzeigen.

Leider scheidet dieser Weg ebenfalls aus, da ein “Click” auf den Button zur Folge hat, dass der jeweils aktive Datensatz der “Button-DataSource” durch die Methode “docCursor” zurück geben wird.
Dies ist soweit auch logisch, da ein Button immer einer DataSource zugeordnet ist (entweder über Angabe in der entsprechenden Eigenschaft des Buttons oder, wenn nicht festgelegt, die erste DataSource der Query).

Wie ist es nun aber möglich, dennoch den zuletzt selektierten (ausgewählten) Datensatz zu ermitteln, wenn die im Standard verwendeten Wege nicht funktionieren?

Um das gewünschte Ziel zu erfüllen (bestimmen, welcher der zuletzt selektierte Datensatz ist) muss eine kleine funktionale Erweiterung der “Info” Klasse durchgeführt werden.

Zuerst müssen in der “classDeclaration” der Klasse “Info” zwei neue Variablen/Buffer zum Speichern des selektierten Datensatzes erstellt werden.

final class Info extends xInfo
{
    #SysTaskRecorderMacro
 
    ObjectIdent         docuView;
    ObjectIdent         lastActivatedForm;
 
    ...
 
    // New code -->     
    Common                  lastSelectedRecord;
    Common                  selectedRecord;
    //New code <--
 
    #Define.CurrentVersion(1)
}
 

Nun müssen noch einige neue Methoden für die Klasse “Info” erstellt werden, damit die Variablen/Buffer geschrieben, abgefragt und gelöscht werden können.

private void setLastSelectedRecord(FormRun _formRun)
{
    ;
    if(_formRun.docCursor())
    {
        if(lastSelectedRecord)
        {
            lastSelectedRecord = selectedRecord;
        }
        else
        {
            //Only get the record data, not the cursor
            lastSelectedRecord = _formRun.docCursor().data();
        }
 
        //Only get the record data, not the cursor
        selectedRecord = _formRun.docCursor().data();
    }
}
 
private void clearLastSelectedRecord()
{
    ;
    lastSelectedRecord.clear();
    selectedRecord.clear();
}
 
common lastSelectedRecord()
{
    ;
    return lastSelectedRecord;
}

 

Zum Schluss müssen diese neu erstellten Methoden noch entsprechend in der Methode “formNotify” aufgerufen werden.

void formNotify(FormRun formRun,FormNotify event)
{
    switch (event)
    {
        case FormNotify::Activate:
            this.activate(formRun);
            if (docu)
                docu.reSearch(formRun);
            //New code -->
            this.setLastSelectedRecord(formRun);
            //New code <--
            break;
        case FormNotify::DeActivate:
            break;
        case FormNotify::Open:
            this.open(formRun);
            if (docu)
                docu.set(formRun);
            break;
        case FormNotify::Close:
            this.close(formRun);
            if (docu)
                docu.clear(formRun);
            //New code -->
            this.clearLastSelectedRecord();
            //New code <--
            break;
        case FormNotify::RecordChange:
            if (docu)
                docu.reSearch(formRun);
            //New code -->
            this.setLastSelectedRecord(formRun);
            //New code <--
 
            if (formRun.isWorkflowEnabled())
            {
                // only refresh controls if current ds equals workflow data source
                if (formRun.objectSet().name() == formRun.workflowDataSource().name())
                    formRun.updateWorkflowControls();
            }
 
            break;
        case FormNotify::NoteClicked:
            if (docu)
                docu.note(formRun);
            break;
    }
}
Durch diese kleine Codeänderung kann nun der zuletzt ausgewählte Datensatz, unabhängig von einer DataSource, abgefragt werden.
void clicked()
{
    Common      currentRecord;
    DictTable   dictTable;
    ;
    super();
    //Get the last selected  record
    currentRecord = infolog.lastSelectedRecord();
 
    dictTable = new DictTable(currentRecord.TableId);
 
    setPrefix(tableid2name(currentRecord.TableId));
    info(strfmt("%1 - %2", currentRecord.(dictTable.titleField1()), currentRecord.(dictTable.titleField2())));
}

Bezogen auf die zuvor beschrieben Anforderung könnte das Ergebnis so aussehen.
 

Maske_CustTable  Maske_SalesTable

Saturday, October 24, 2009 5:45:25 PM (Mitteleuropäische Zeit, UTC+01:00)  Axel Kühn  #    Comments [0] - Trackback
 |  |  | 



Translate
Über/Kontakt

     







© Copyright 2010 Axel Kühn
Sign In
Subscribe this blog
Blogroll
 Arijit Basu
 Axapta Blog
Blog around Microsoft Business Solutions Axapta by Helmut Wimmer
 BlaBlubBlog
Der Blog von Kai Gloth
 Dave Bowles
 Dick Wenning
Ax(apta) start pages
 Fred Shen
 Harish Mohanbabu
 jinx´s AX Blog
Everything about Microsoft Dynamcis AX
 Lars Keller
All about .NET, VSTS, VSTO and more
 Max Belugin
 TaReMoTi Blog
Der Blog von Karsten Döring
Archiv
<July 2010>
SunMonTueWedThuFriSat
27282930123
45678910
11121314151617
18192021222324
25262728293031
1234567
Statistik
Total Posts: 129
This Year: 11
This Month: 0
This Week: 0
Comments: 46





All Content © 2010, Axel Kühn
DasBlog theme 'Business' created by Christoph De Baene (delarou)