SBX - Search With Button

SBX - Forum Post Title

Form loading performace

Microsoft Dynamics AX Forum

JMu asked a question on 24 Feb 2016 8:35 AM

Question Status

Verified

Hi,

We have implemented a feature to highlight settled rows in custTrans form. So when user selects a row all transactions that are settled with the selected transaction are highlighted. This works fine for most time but if customer has like thousands of transactions there is major performance impact.

The implementation is actually copied from tutorial_Form_DispalyOptions which seems to suffer from same kind of performance issue.

Basically the problem is when we need to change the highlighted rows when user select a new row. First we clear old displayoptions with this code

  for (bufferLocal = custTrans_ds.getFirst(); bufferLocal; bufferLocal = custTrans_ds.getNext())
        {
            custTrans_ds.clearDisplayOption( bufferLocal );
        }

Now this basically loads and selects all the custTrans records for the customer one by one to clear the old display options. Most of the rows were not originally actually loaded/rendered on form.

Is there any way to call the clearDisplayOption specific record in the custTrans_ds instead of iterating through all of them?

Reply
Brandon Wiese responded on 24 Feb 2016 8:57 AM
My Badges
Suggested Answer

There are much easier approaches to what you are doing.

But, you could speed up your approach by keeping track in a Set variable which rows you have highlighted, and only loop through and clear those rows, thus avoiding the massive loop and loading in unnecessary records.

Reply
Brandon Wiese responded on 24 Feb 2016 10:24 PM
My Badges

In your original post, you said "when user selects a row".  How is that done?  Are you doing the highlighting in the data source active() method such that the focus on any row causes other rows to be highlighted?  Is it in response to a record being marked?  Or do the rows highlight in response to a button being pushed?

Reply
JMu responded on 25 Feb 2016 3:03 AM

The highlighting is done in the active() method of the datasource.

I tried now to store the highlighted records into a set and then go through the set in order to clear previous highlighting after focus changed to new row. This worked well for clearing the highlighting but new rows are no longer highlighted.

It seems that as the FormDataSource.DisplayOption() was called "automatically" for each row when looping through and calling the clearDisplayOption() method. No that the loop is no longer done the DispalyOption() is not called again. I don't know if it can be called manually because it seems that the parameter FormRowDisplayOption is a kernel type that cannot be instantiated correctly in x++ code.

Reply
Brandon Wiese responded on 25 Feb 2016 7:38 AM
My Badges
Verified Answer

I found the same problems.  But your post gave me an idea.

If the grid display code calls .displayOption() only when it displays the record for the first time, and then remembers the display options forever, that would explain it.  So if we think of .clearDisplayOption() more as a reset cache method, where it causes that row to call .displayOption() the next time it is displayed, then I think we can make this work.

Here are two methods I added to the CustTrans data source in form CustTrans.

The displayOption is simple.  If there's a set of settledTransactions, and the current RecId is in that set, turn the current row pink.

public void displayOption(Common _record, FormRowDisplayOption _options)
{;
    if (settledTransactions)
    {
        if (settledTransactions.in(_record.RecId))
            _options.backColor(WinAPI::RGB2int(255,240,240));
    }

    super(_record, _options);
}

The selectSettledTransactions(..) method does the heavy lifting.  First it loops through everything in the set calling .clearDisplayOption(), then it re-initializes the set variable, and then populates it with a new set of RecId's based on the provided_custTrans record.  The change I made this morning is to add .clearDisplayOption() not just to the rows that were pink and are returning to a standard background, but also the rows I want to make pink.  This seems to cause those rows to call .displayOption() the next time they pass into view, or immediately if they are currently in view, and then the displayOption() method above fires immediately.

private void selectSettledTransactions(CustTrans _custTrans)
{
    CustSettlement              custSettlement;
    SetEnumerator               e;
    RecId                       recId;
    ;

    if (settledTransactions)
    {
        e = settledTransactions.getEnumerator();
        while (e.moveNext())
        {
            recId = e.current();
            CustTrans_ds.clearDisplayOption(CustTrans::find(recId));
        }
    }

    settledTransactions = new Set(Types::Int64);  // RecId

    while select custSettlement
        where custSettlement.TransRecId == _custTrans.RecId
    {
        recId = custSettlement.OffsetRecid;
        CustTrans_ds.clearDisplayOption(CustTrans::find(recId));
        settledTransactions.add(recId);
    }

    this.refreshEx(-1);
}

The .refreshEx(-1) seems to work better than just .refresh() for some reason.

Then in the active() method I just added this one line below the super().

    this.selectSettledTransactions(custTrans);

I get very fluid and fast behavior with what I've posted here.  I did notice some oddness with the first set of rows that are highlighted from the first active() call.  Maybe something strange with the event sequence, I'm not sure yet.  

How does it work for you?

Reply
Brandon Wiese responded on 25 Feb 2016 8:03 AM
My Badges

Just for completeness in case someone stumbles across this thread in the future, the following line is added to the classDeclaration also in form CustTrans.

    Set                             settledTransactions;
Reply
JMu responded on 25 Feb 2016 8:58 AM

Thanks! Works very well now.

Reply
Brandon Wiese responded on 25 Feb 2016 7:38 AM
My Badges
Verified Answer

I found the same problems.  But your post gave me an idea.

If the grid display code calls .displayOption() only when it displays the record for the first time, and then remembers the display options forever, that would explain it.  So if we think of .clearDisplayOption() more as a reset cache method, where it causes that row to call .displayOption() the next time it is displayed, then I think we can make this work.

Here are two methods I added to the CustTrans data source in form CustTrans.

The displayOption is simple.  If there's a set of settledTransactions, and the current RecId is in that set, turn the current row pink.

public void displayOption(Common _record, FormRowDisplayOption _options)
{;
    if (settledTransactions)
    {
        if (settledTransactions.in(_record.RecId))
            _options.backColor(WinAPI::RGB2int(255,240,240));
    }

    super(_record, _options);
}

The selectSettledTransactions(..) method does the heavy lifting.  First it loops through everything in the set calling .clearDisplayOption(), then it re-initializes the set variable, and then populates it with a new set of RecId's based on the provided_custTrans record.  The change I made this morning is to add .clearDisplayOption() not just to the rows that were pink and are returning to a standard background, but also the rows I want to make pink.  This seems to cause those rows to call .displayOption() the next time they pass into view, or immediately if they are currently in view, and then the displayOption() method above fires immediately.

private void selectSettledTransactions(CustTrans _custTrans)
{
    CustSettlement              custSettlement;
    SetEnumerator               e;
    RecId                       recId;
    ;

    if (settledTransactions)
    {
        e = settledTransactions.getEnumerator();
        while (e.moveNext())
        {
            recId = e.current();
            CustTrans_ds.clearDisplayOption(CustTrans::find(recId));
        }
    }

    settledTransactions = new Set(Types::Int64);  // RecId

    while select custSettlement
        where custSettlement.TransRecId == _custTrans.RecId
    {
        recId = custSettlement.OffsetRecid;
        CustTrans_ds.clearDisplayOption(CustTrans::find(recId));
        settledTransactions.add(recId);
    }

    this.refreshEx(-1);
}

The .refreshEx(-1) seems to work better than just .refresh() for some reason.

Then in the active() method I just added this one line below the super().

    this.selectSettledTransactions(custTrans);

I get very fluid and fast behavior with what I've posted here.  I did notice some oddness with the first set of rows that are highlighted from the first active() call.  Maybe something strange with the event sequence, I'm not sure yet.  

How does it work for you?

Reply
Brandon Wiese responded on 24 Feb 2016 8:57 AM
My Badges
Suggested Answer

There are much easier approaches to what you are doing.

But, you could speed up your approach by keeping track in a Set variable which rows you have highlighted, and only loop through and clear those rows, thus avoiding the massive loop and loading in unnecessary records.

Reply

SBX - Two Col Forum

SBX - Migrated JS