Good day.
I’ve noticed this problem for a long time, but I couldn’t report it because I couldn’t reproduce it on a small scale, until I finally connected all the dots.
Take this script as an example:
function Ontest(scriptCmdData) {
DOpus.ClearOutput();
var dlg = scriptCmdData.func.dlg();
dlg.template = 'dialog1';
dlg.Create();
var listview = dlg.Control('listview');
var static = dlg.Control('static');
var btn = dlg.Control('btn');
var row, objs = {};
for (var i = 0; i <= 5; i++) {
objs[i] = {
'name': 'ID' + i,
'value': NewValue(10)
};
row = listview.GetItemAt(listview.AddItem(objs[i].name, i));
if (row) {
row.subitems(0).text = objs[i].value;
objs[i].pos = row.index; //used just for logging purposes
}
}
listview.columns.autosize();
dlg.Show();
var msg, sel_id = -1;
listview.value = 0;
while (true) {
msg = dlg.GetMsg();
if (!msg.result) break;
if (msg.event === 'click' && msg.control === 'btn') {
if (sel_id < 0) continue;
Log('name=' + objs[sel_id].name + '; id=' + sel_id + '; value=' + objs[sel_id].value);
row = listview.GetItemByName(objs[sel_id].name);
if (row) {
Log('row_name=' + row.name + '; row_id=' + row.data + '; row_pos=' + row.index);
row.subitems(0).text = NewValue(10);
listview.columns.autosize();
static.label = (row.index !== objs[sel_id].pos ? ('<#FF00FF>Wrong pos from row "' + row.name + '". Expected "' + row.index + '", but received "' + objs[sel_id].pos + '" instead') : ('Last change:' + row.name + ':' + row.subitems(0).text));
}
}
else if (msg.event === 'selchange' && msg.control === 'listview') {
Log('id=' + msg.data + '; pos=' + msg.index);
sel_id = msg.data;
btn.enabled = sel_id >= 0;
}
}
}
dlg_test.opusscriptinstall (1.1 KB)
I tend to use the data value from Control.AddItem(value, data)
as an ID to associate an object with a row and its data.
And since there are two ways to get a DialogListItem
object: by index and by name, not by that data value. But the position can change when you sort the content (if columns are sortable), I thought getting by name would be the right approach. But I realized that once you've sorted by any column at least once, Control.GetItemByName()
returns the wrong object. Or in other words, it returns the object at its original position, even if it visually appears elsewhere. That means if you make a change to the list, it applies to the wrong row, and if it's a long list, it can look like no value changed at all.
Now that I've found the problem, the workaround is to store the initial position and use Control.GetItemAt()
instead with that value, which, also incorrectly (because the position changed from its initial one), gives you the correct row visually. I know it sounds confusing .
In summary, after sorting the list
there's a mismatch between what you see and what you get when you request a DialogListItem
by name, even though the name obviously stays the same. As far as I understand, this seems like a bug, right? Or am I missing something?
And since the ID (or data) that the user assigns to each row is less likely to change (because it’s user-defined and should be unique, unlike the "name"), could a Control.GetItemByID()
or something similar be added
?
I hope this makes sense!