Jump to content
Tang

Delete a ListView Item together with its livebinding DB record.

Recommended Posts

I built a multi-device app using FireMonkey.

I have a ListView Live-Binding to a DB. Both synched by *.

It all works normally until I left wipe an item to delete. The item can be deleted, but the DB record is not.

So following Doug Rudd advice, implemented following code to store DBID and locate the deleting Item.

procedure TPassPlus.LinkListControlToField1FilledListItem(Sender: TObject;
  const AEditor: IBindListEditorItem);
begin
     (AEditor.CurrentObject as TListItem).Tag :=
     DB_Table.FieldByName('DBID').AsInteger;
end;

myDBID:=     ListView1.Selected.Tag.ToString;
if DB_Table.Locate('DBID',myDBID,[]) then DB_Table.delete;

It worked well to delete the DB record. However, when ListView1DeletingItem event finished, it generated a 'Argument out of range' error, which can be traced into TPresentedListView.DoDeleteItem event. It looks like, when DB record deleted, Listview has deleted the correspoding item, so when ListView1DeletingItem event finished, ListView has nothing to delete. What is the solution?

I was trying to decouple the link between the DB and Listview at runtime so I can delete the record and re-link the two. I tried following code as a test.

   procedure TPassPlus.ListView1DeletingItem(Sender: TObject; AIndex: Integer;
      var ACanDelete: Boolean);
    begin 
        ListView1.BeginUpdate;
      BindSourceDB1.DataSource.DataSet.close;
    //or LinkListControlToField1.Active:=false;
        ListView1.EndUpdate;
end;

On either case, it will produce 'Argument out of range' error. What is the way to do this simple task?

Share this post


Link to post

Hi,

Well, I don't understand the goal, I never use this DeletingItem method, but I will investigate.

So to be clear : You have  a TListView  filled with livebindings, how do you :

14 hours ago, Tang said:

I left wipe an item to delete.

A gesture, I think, but the code? (I am not a gesture expert) 

Sorry to disappoint, but I'm not that far (I have not encountered this need in my professional life)

 

Share this post


Link to post
51 minutes ago, Uwe Raabe said:

Wipe Left to Delete

Ok, but I try this on a windows pc how can I "simulate" this wipeleft ?

 

On another hand, with a "classic" windows app (D11 Alexandria). I found that Deleting last item of the list raise an  'access violation' !

procedure TForm1.LinkListControlToField1FilledListItem(Sender: TObject;
  const AEditor: IBindListEditorItem);
begin
(AEditor.CurrentObject as TListItem).Tag :=
     FDTable1.FieldByName('ID').AsInteger;
end;

procedure TForm1.ListView1ButtonClick(const Sender: TObject;
  const AItem: TListItem; const AObject: TListItemSimpleControl);
begin
if FDtable1.Locate('Id',AItem.Tag) then FDtable1.Delete;
end;

 

Capture.PNG

Share this post


Link to post

So, I test this on Android. @Tang  I can submit you this solution

Add a private variable (in my code   key : integer;)

procedure TForm1.ListView1DeleteItem(Sender: TObject; AIndex: Integer);
begin
if FDMemtable1.Locate('id',key) then fdmemtable1.Delete; // delete the record
end;

procedure TForm1.ListView1DeletingItem(Sender: TObject; AIndex: Integer;
  var ACanDelete: Boolean);
begin
key:=listView1.Items[aIndex].Tag; // get the key to delete
ACandelete:=true;
end;

But, yes, there is one, I think there is a bug I wrote in the prior post :

 

23 hours ago, Serge_G said:

 Deleting last item of the list raise an  'Out of range' error !

 

Edited by Serge_G
not an 'access violation' error but an 'Out of range' one

Share this post


Link to post
6 hours ago, Uwe Raabe said:

Wipe Left to Delete is a standard functionality in FMX-TListView.

The "wipe-left" feels also not very iOS-UX-standard-like, that is what my clients complain.

So I tried to remove that, by some other methods.

Share this post


Link to post

Thanks Serge, 

 

Indeed, it worked for me as well. 

It means 

ListView1DeletingItem

is only for retrieving the DB record 'id' which is bound to the deleting ListView.Items[AIndex] and 

 

ListView1DeleteItem

is for DB delete work. 

 

For my case, when I delete the DB record, my ListView has no data to show. So, I have to close and reopen the DB to let the ListView to show the data. Not sure if you had similar issue. 

 

The whole point of this question is to find a way , when user delete a Listview item, it will also safely delete the livebinding DB record. I thought this is very straight forward operation. In fact, Item.delete is not linked to DB record deleting automatically. I guess this is about LinkListControlToField1. This is a one way binding, not bi-directional. So. cause the trouble. 

And in ListView1DeletingItem event, we cannot do any deletion, it will cause many different kinds of error because the ListView index and DB record index. If you have a search box working, things will get more complicated. Here, we can only get a DBID related to the deleting Item. then in ListView1DeleteItem event do the DB.delete. 

 

It seems working now, thanks for all your helps. 

 

I did not have a 'access violation' ! error when delete the last record. But I did see some posts mentioned similar issue. Maybe need BeginUpdate/EndUpdate?

 

'wipe-left' is quite handy for deletion. For instance, on iOS Notification Page, you will receive many notifications from various APPs. They can be wiped off. Email App uses this to delete email.  But I guess Serge's delete button seems not a native FMX ListView delete button. Did you added by your own? That may cause the ‘access error’. You can only wipe one item therefore, only 1 button will be shown. Yours shows all the buttons. My APP's Listview is here. It works on windows and mobile OS consistently. 

 

Temp1.png

Edited by Tang
  • Like 1

Share this post


Link to post
8 hours ago, Tang said:

But I guess Serge's delete button seems not a native FMX ListView delete button. Did you added by your own? That may cause the ‘access error’.

Hi,

No, the image I post was a "classic" ImageListItemRightButton Item appearance (with TextButton visible) , and ImageListItemRightButtonDelete for the ItemEdit appearance.

 

The "access error", I got it when I try to use a ListView1.DeleteItem(AItem.Index); beforehand declared as an helper (only way I found to raise OnDelete/Ondeleting event with touch input unavailable.

  TListViewHelper  = class helper for TListView
    public function DeleteItem(const ItemIndex: Integer): Boolean; end;
    
{ TListViewHelper }

function TListViewHelper.DeleteItem(const ItemIndex: Integer): Boolean;
begin
inherited;
end;    

And using the OnButtonClick event of TListView (guilt, the  TListItem.MouseUp event)

 

Using the OnItemClick to use DeleteItem

procedure TForm1.ListView1ItemClick(const Sender: TObject;
  const AItem: TListViewItem);
begin
ListView1.DeleteItem(AItem.Index);
end;

I have no "access error"

 

8 hours ago, Tang said:

I did not have a 'access violation' ! error when delete the last record. But I did see some posts mentioned similar issue.

Sorry, it was an "argument out of range" not an "access violation"  (guilty TListItemView.GetObject).

My test (on Android), shows me that if there is only one item (the one to delete) this exception does not raise.

8 hours ago, Tang said:

Maybe need BeginUpdate/EndUpdate?

Yes, perhaps a bypass but in wich event ?

 

 

Edited by Serge_G

Share this post


Link to post
8 hours ago, Tang said:

It means 


ListView1DeletingItem

is only for retrieving the DB record 'id' which is bound to the deleting ListView.Items[AIndex] and 

 


ListView1DeleteItem

is for DB delete work. 

Yes, but if I do so, it's because the AIndex argument of OnDelete event is always 0 ! (what a strange thing no ?)

Share this post


Link to post

I think that is the Pro and Con for LiveBinding.:classic_biggrin: It is easy to use but with bugs or big improvement space. 

It handles the link, update, delete, index etc between Listview and the datasource. We cannot do any change, otherwise it will mess up the relationships between the 2 easily.  ListView1DeleteItem event is the place where we can 'change' work.  But occasionally, I will have 'access violation error'. I am still not figuring out when and why, error not reproducible.

Share this post


Link to post
14 minutes ago, Serge_G said:

Yes, but if I do so, it's because the AIndex argument of OnDelete event is always 0 ! (what a strange thing no ?)

ListView1DeletingItem

already deleted the Listview.item[AIndex].

then it comes to 

ListView1DeleteItem

so, here AIndex is always 0, ( guess being reset after the ListItem was deleted). 

So, we need to get the DB id associated with the ListItem in ListView1DeletingItem event. In this event, we still have the Item and its Tag ...

  • Sad 1

Share this post


Link to post

Tang, I'm struggling with the same issue.

If you managed to do anything about it I would greatly appreciate it if you can share it with me or workaround around this.

Thanks

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×