The issue we're talking about here is this:
- There is an AX form which users make their own personalisations to, moving some of the fields around, or perhaps adding other fields (via the right click->setup functions).
- Then I need to redevelop this form a bit - a couple of new fields are added via the AOT.
- Now when user's try to load the form it might crash - particular if I have changed the controls on a grid. So first I need to install a hotfix to stop the crash, it was fixed in KB2253378 (5.0.1500.3077 onwards) but as always just implement the newest kernel you can get your hands on.
- Now when users log in, the crash is stopped, but their saved user settings are not applied to the form, it is back as default layout.
The user settings are stored in the SysLastValue container (SYSLASTVALUE.VALUE). You may have looked at the structure of the sysLastValue data via the usage data form (from user options) before, it just looks like a load of numbers, and it's hard to relate them back to the form. Well I found that the data in the container is basically the form control IDs, stored in a structure to match the structure of the form design.
When I make a change to the form's design in the AOT, for example I add a field to a grid, then this can push all of the existing control IDs up by one, a control that was previously 12301, is now 12302. Now because we use these IDs to match to the layout held in SysLastValue - you can understand how a change to the design in the AOT invalidates the SysLastValue data.
So attached is an xpo (scroll to the bottom) which can rebuild SysLastValue data for a form where the control IDs have changed. You set which form you want to rebuild data for, then it instantiates an instance of that form and then for each record in SysLastValue which relates to that form it iterates through and converts the IDs in SysLastVaue if it finds that they are different from the current form design.
Warning! This code will update the usage data in an unrecoverable way so please take great care when using it - test it first and take a copy of the SysLastValue table before updating it for real. It would be pretty awful to try to help users by recovering their usage data for them and end up making it worse, so please be careful.
Few points about using it:
- Just run the main() - note that the form name to update is hardcoded in here as "purchTable" at the moment and needs to be changed to whichever form you need.
- This is for AX2009 only at the moment (because I use a task recorder function which might not be available in AX4 as standard).
- It picks up the container in SysLastValue.Value and then iterates through it checking the ID for each control that it finds (using a function from task recorder which can return form control IDs) and then updating the container back.
- This accounts for moving of fields or adding new fields within a parent control. This is a key point - there are an infinite number of possible changes that could be made to the structure of a form, this really only caters for fields being added/moved within their parent control (i.e. doesn't account for moving controls from one parent to another).
- It should be ok with user added fields, unless the ID of a newly added field conflicts with a user added field (it shouldn't - they are +250 IDs higher).
What I expect the process for a developer to be is:
- They make their form changes as normal and they are tested etc..
- When they move the form to live environment, either via XPO or layer they need to run this class for that form to update the sysLastValue data.
- This needs to be done with no one on the system using that form and before anyone opens the new form (as opening it once will damage the user's default sysLastVaue record for that form and my class can't correct it then).