使用临时TListItems

时间:2018-07-11 16:17:42

标签: delphi delphi-xe2

我想在后台刷新listview的列表,为此我创建了一个临时的TListItems,但是我无法将其分配给我的listview。如果我创建TListItems和TListItem,则会发生访问冲突错误;

 var
  lis:TListItems;
  li:TListItem;
begin
  lis := TListItems.Create(nil);
  try
    li := TListItem.Create(nil);
    li.Caption := 'test'; // at this line av occurs
    lis.AddItem(li);
    ListView1.Items.BeginUpdate;
    try
      ListView1.Items.Assign(lis);
    finally
      ListView1.Items.EndUpdate;
    end;
  finally
    lis.Destroy();
  end;

如果我在创建TListItems时使用ListView1作为所有者,则不会出现新行;

 var
  lis:TListItems;
  li:TListItem;
begin
  lis := TListItems.Create(ListView1);
  try
    li := TListItem.Create(lis);
    li.Caption := 'test';
    lis.AddItem(li);
    ListView1.Items.BeginUpdate;
    try
      ListView1.Items.Assign(lis);
    finally
      ListView1.Items.EndUpdate;
    end;
  finally
    lis.Destroy();
  end;

所以我想在后台准备一个新列表并将其分配给listview,我该怎么办?

注意:准备列表需要很长时间,这就是为什么我在后台准备它。 (我通过线程填充列表,并使用TRTLCriticalSection保护列表)

1 个答案:

答案 0 :(得分:1)

TListItemsTListItemTListView紧密相连,因此不能像您尝试的那样以独立方式使用。 TListItemsTListItem都委托给TListView处理他们的工作。

在第一个示例中,您获得了AV,因为没有分配TListView来处理工作。

在第二个示例中,新列表项未正确显示,因为在分配其Caption时尚未将其添加到ListView,因此属性设置程序没有任何更新。并且AddItem()不会将现有属性值应用于新插入的列表项。必须使用单个属性设置器代替。

您必须首先使用TListItems.Add()方法,而不是直接调用AddItem(),然后您可以根据需要修改新的TListItem,例如:

var
  NewList: TStringList;
  Lock: TCriticalSection;

...

// in a worker thread...

Lock.Enter;
try
  NewList.Clear;
  NewList.Add('test');
  ...
finally
  Lock.Leave;
end;
// signal main UI thread that a new list is ready ...

...

// in the main UI thread when the signal is received...

var
  li: TListItem;
  i: Integer;
begin
  Lock.Enter;
  try
    ListView1.Items.BeginUpdate;
    try
      ListView1.Items.Clear;
      for i := 0 to NewList.Count-1 do
      begin
        li := ListView1.Items.Add;
        li.Caption := NewList[i];
        ...
      end;
    finally
      ListView1.Items.EndUpdate;
    end;
  finally
    Lock.Leave;
  end;
end;

但是,正如David H在评论中所说,在虚拟模式下使用ListView(将OwnerData属性设置为true并使用TListView.OnData...事件)是解决此问题的更好方法情况:

var
  NewList: TStringList;
  Lock: TCriticalSection;

...

// in a worker thread...

Lock.Enter;
try
  NewList.Clear;
  NewList.Add('test');
  ...
finally
  Lock.Leave;
end;
// signal main UI thread that a new list is ready ...

...

// in the main UI thread...

private
  MyListItems: TStringList; // or whatever you want to use to store your item data

...

begin
  Lock.Enter;
  try
    MyListItems.Assign(NewList);
  finally
    Lock.Leave;
  end;
  ListView1.Items.Count := MyListItems.Count;
end;

procedure TMyForm.ListView1Data(Sender: TObject; Item: TListItem);
begin
  Item.Caption := MyListItems[Item.Index];
  ...
end;