Saturday, February 25, 2012

Refresh DataSource and retain position

Refresh
a DataSource is a very common task to Dynamics AX developers, as you'll most
likely perform changes on a record and have to present it to the user, on a form.

The
most commonly used method to refresh the DataSource to make a form show what
you have changed on a record is the research method.

The only problem is that the research method
doesn't retain the record that was selected, it positions the DataSource on the
first record of the result, causing the user to see another record. To resolve
this matter, the research method, only in Dynamics AX 2009, has a boolean
parameter, retainPosition. Now if you call it by passing true to
it, it will sure retain the position of the selected record after the refresh,
right? Wrong...

This should only work when your form has DataSources linked by
Inner Joins in it, what means that the generated query has Inner Joins in it.
Having any other link types or temporary tables causes it to not retain
the position, even if you pass true when calling it.

So I'll present you two ways of retaining the position of the
selected record, one that works sometimes, and one that always works,
although you should always try and see if it works with research(true) before
trying anything else.

On the first way, you could simply get the
position of the DataSource before calling research(), like this:

int position;

;

position =
myTable_ds.getPosition();

myTable_ds.research();

myTable_ds.setPosition(position);

But
does this work perfectly? Not again...

The code above should select the record that was on the previously
selected record's position. What does that mean? It means that if your query
result changes the record's orders, you won't have the correct record selected.
This could easily happen if your form handles the records' order in a special
way, or if the action is performed when the record or any records are inserted,
which will certainly cause the the form to reorder the records when you tell it
to refresh the DataSource.

The second way to do it will actually look for the correct record
and then select it, so you can imagine it will perform a little worse than the
others, but at least it will never fail (unless you, somehow, delete the record
you're looking for in the meantime).

Simply
copy the RecId from the record you want to keep selected to a new table buffer,
like this:

We copy
if to a new table buffer because the findRecord method expects a
parameter of type Common. If you stored the RecId in a variable, you would
have to pass it to a table buffer anyway...

And that's it, it'll first refresh the
DataSource, and then look for your record and select it, so the screen might
even "blink" for a second. As I said, this is not the best when
thinking about performance, but at least it works...