TListView is a very complex component. What we see in the LCL properties scratches only the surface, the bulk of the operations is done behind the scene by the widgetset. So whatever you do with the LCL properties must be passed on the widgetset where it is finally handled.
As for replacing an image in the imagelist, the problem is that the widget must be notified of the change. In the ImageIndex setter of the TListView this is done by calling the ItemSetImage method of the widget class. Since this method is not accessible from the outside, I think the most straightforward way to inform the widget about the image change is to call the ImageIndex setter. But this is not executed when there is no change at all, therefore we must set the ImageIndex to -1 before:
procedure TForm1.btReplaceSelClick(Sender: TObject);
var
p: TPicture;
oCap: String;
imgIdx: Integer;
begin
if (ListView1.Selected<>nil) and OpenPictureDialog1.Execute then
begin
imgIdx := ListView1.Selected.ImageIndex;
p:= TPicture.Create;
p.LoadFromFile(OpenPictureDialog1.FileName);
ImageList1.Replace(imgIdx, p.Bitmap, nil);
p.Free;
ListView1.Selected.ImageIndex := -1;
ListView1.Selected.ImageIndex := imgIdx;
end;
end;
Some similar caching seems to be involved when the listview is initially created. There is a Flags property in TListItems which is an empty set after streaming the ListView from the lfm file, but after your call to ReadData this flags are at [lisWSItemsCreated]. I don't know whether this causes the different behaviour, and it does not matter after all since the Flags are not writeable from the outside. But looking at the ListView component editor in unit ListViewPropEdit (in packages/ideintf) there is an idea how to do it correctly:
procedure TListViewItemsEditorForm.SaveToList;
var
I, J: Integer;
Node: TTreeNode;
Item: TListItem;
begin
if Assigned(FListView) then
begin
FListView.BeginUpdate;
try
FListView.Items.Clear;
//Recreate new items or modify
for I := 0 to TreeView1.Items.Count - 1 do
begin
Node := TreeView1.Items[I];
if Node.Level = 0 then
begin
Item := FListView.Items.Add;
Item.Caption := Node.Text;
Item.ImageIndex := Node.ImageIndex;
Item.StateIndex := Node.StateIndex;
//SubItems
for J := 0 to Node.Count - 1 do
begin
Item.SubItems.Add(Node.Items[J].Text);
Item.SubItemImages[J] := Node.Items[J].ImageIndex;
end;
end;
end;
finally
FListView.EndUpdate;
end;
FModified := True;
end;
end;
So, simply call ListView1.Clear at the beginning of your LoadImgFile, and the items will be displayed with their images.