TTMSFNCListBox returns random itemindex if BeginUpdate/EndUpdate is used

Without the BeginUpdate/EndUpdate the following code works OK

list.BeginUpdate; 
with list.Items do try 
 Clear;
 for var c in qus do 
  with add do begin
  text:='some text';
  DataObject:=c;
  end;
list.EndUpdate;
Assert(list.itemindex<=list.Items.Count);

We have tested this here and don't get an error. I'm not sure what c & qus is and how many items are added? Also, are there items added before clearing the list? Please provide more details.

  • It happens in VCL but I noticed the same in FMX
  • qus is a Tlist<Tsomethingobject>, so c is the Tsomethingobject
  • Yes, usually there are items before clearing the list

It happens (Itemindex has a wrong value) in

procedure TTMSFNCCustomListBox.EndUpdate;
begin
  inherited;
  if Assigned(FTreeView) then
  begin
    Dec(FUpdateCount);
    FTreeView.EndUpdate;
    SelectedItem := FSaveSelectedItem;
  end;
end;

after the FTreeView.EndUpdate;

We'll further investigate this here, in the meantime you can manually set the value to make sure it lies within the items count.

Try the following code, keep pressing the button until you get the error

unit Unit4;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, VCL.TMSFNCTypes, VCL.TMSFNCUtils,
  VCL.TMSFNCGraphics, VCL.TMSFNCGraphicsTypes, Vcl.StdCtrls,
  VCL.TMSFNCCustomControl, VCL.TMSFNCListBox;


type
  TForm4 = class(TForm)
    list: TTMSFNCListBox;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form4: TForm4;

implementation

{$R *.dfm}

procedure TForm4.Button1Click(Sender: TObject);
begin
list.BeginUpdate;
with list.Items do try
 Clear;
 for var n:=0 to trunc(random(20))+1 do
  with add do begin
  text:='some text '+n.ToString+'<br>something';
  end;
finally list.EndUpdate; end;
Assert(list.itemindex<=list.Items.Count);
if (list.Items.Count>0) and (list.ItemIndex<0) then list.SelectItem(0);
end;

end.

You will notice also that sometimes, with items inside the Listbox, the first item is not selected as expected by the above code

It tries to preserve the item and then resets it, but unfortunately the current implementation does not take Clearing into account, so for now, please set the ItemIndex to 0, or to a value within the Item count, to make sure that the error does not occur.

The same problem happens sometimes with list.SelectedItem:=something;
Did you reproduced the initial Endupdate problem?
Thank you in advance

The TTMSFNCListBox.ItemIndex in many cases returns values bigger than TTMSFNCListBox.items.count.
It does not happen only with Endupdate, finally.
Not checking it always before using it, it makes the TTMSFNCListBox unusable.
I have created a class helper till having a fix.
Did someone else have the same problem?

It's unclear exactly what you mean. The code clears all the items, which means that the ItemIndex is invalid at that point. You know how many items you add after the clear, so you can just add:

  list.BeginUpdate;
  with list.Items do
    try
      Clear;
      for var n := 0 to trunc(random(20)) + 1 do
        with add do
        begin
          text := 'some text ' + n.ToString + '<br>something';
        end;
    finally
      list.EndUpdate;
//      list.ItemIndex := 0;
//      or
//      list.ItemIndex := List.Items.Count - 1
    end;

I can't see a reason why ItemIndex would return an invalid value after forcing it to a value within Items.Count.

Finishing a project and using many TTMSFNCListBox I am getting a lot of sporadic errors that all of them are due to Itemindex values that are bigger than the items.count. It is not a problem of Endupdate as I can figure now. I had the same strange problems when trying to use it last month in FMX but I finally substituted with an other Listbox component.
Today with the following class helper and using only Itemindex for setting selected item everything works OK.

unit fnclistboxfake;

interface
uses VCL.TMSFNCListBox;

type TTTMSFNCListBoxfake=class helper for  TTMSFNCListBox
        public
          function Itemindex2:integer;
end;


implementation

{ TTTMSFNCListBoxfake }

function TTTMSFNCListBoxfake.Itemindex2: integer;
begin result:=itemindex; if result>=items.Count then result:=-1; end;

end.

I do not know what I can do more to help for correcting this issue.

I already acknowledged that the BeginUpdate & EndUpdate does not take a Clear into account, so for now, manually setting the ItemIndex will fix the issue. We have internally added the necessary checks to make sure ItemIndex is not out of bounds, the next version will have this included.

1 Like