Jump to content
softtouch

Listview prevent change of item

Recommended Posts

I have a listview (report mode) and a memo.

The listview has items, when an itrem is clicked, the memo is filled with some data related to the listview item.

When the data in the memo is changed/modified, and the user click on another listciew item or the empty space in the listview, I want to popup a messagebox telling the user about the modification and if he want to continue.

If he select to not to continue, I want that the listview does not change the item.

Unforetunately, onSelectItem with a messagebox in it wont work, its called twice.

onChanging also is called twice, even I set AllowChange to false.

 

So how can I have a messagbox in any of the event without it being called twice?

Share this post


Link to post
Posted (edited)

This is not a good design choice.  I do not recommend implicitly updating the current list item when selecting another item.  I would instead suggest that you use a separate button or other UI element that the user must activate explicitly to commit any changes to the current list item.  If they select another list item without committing changes, then the changes are simply discarded when the new list item's details are displayed.

Edited by Remy Lebeau

Share this post


Link to post
1 minute ago, Remy Lebeau said:

This is not a good design choice.  I do not recommend implicitly updating the current list item when selecting another item.  I would instead suggest that you use a separate button/etc that the user must hit intentionally to commit any changes to the current item.  If they select another item without committing changes, then the changes are simply discarded when the new item's details are displayed.

That is what it is currently doing, but user complain that they lost lots of changes because they forgot to click that button. I am now playing with the virtualtreeview, that seems to work better.

Share this post


Link to post
Posted (edited)
15 hours ago, softtouch said:

That is what it is currently doing, but user complain that they lost lots of changes because they forgot to click that button.

Well, then that is the user's problem, not yours.  They need to pay closer attention to what they are doing.

 

If you absolutely must do what you are asking for, then you need to take into account that in a ListView, a single user action triggers multiple state changes, which is why you are getting multiple events fired.  For instance, a list item can gain/lose focus and gain/lose selection, which are separate attributes, so changes to them may or may not be reported in a single event.

 

When you select a list item and then select another item, the old item has to be de-deleted and de-focused, and then the new item has to be selected and focused.  So, that is up to 4 distinct events that could occur (maybe less, if the ListView coalesces them).  And while the OnChanging and OnSelectItem events do tell you which list item is changing, and even that a state change is occurring, but they don't tell you everything the ListView reports, namely the old and new state values.

 

You could try subclassing the ListView to handle the LVN_ITEMCHANGING and LVN_ITEMCHANGED notification directly, which give you much more details about which attribute(s) are changing/changed, and what the old and new value(s) are.  However, even though LVN_ITEMCHANGING does let you cancel a change, it doesn't actually cancel the entire user action.  So, for example, if you have Item 1 selected and then try to select Item 2, you can disallow the de-selecion of Item 1, but Item 2 can/will still become selected.

 

Unfortunately, a ListView control simply does not give you enough control to cancel the user action as a whole.  So, you are going to have to get a little creative.  Such as having the OnChanging event block every change that you don't initiate in code, and then track the user's mouse and keyboard activity to change the ListView selection in code.  Or, if the MessageDlg says to cancel, then have OnChanging block all subsequent changes for X amount of time. Etc.

 

Edited by Remy Lebeau

Share this post


Link to post

Thank you for the detailed information. I decided to go with a virtualstringtree, and that seems to work as expected.

Share this post


Link to post
procedure TForm1.lv1Change(Sender: TObject; Item: TListItem; Change: TItemChange);
begin
  if Item.Focused and Item.Selected then
  begin
    // your code here
  end;
end;

 

Share this post


Link to post

@SnowSonic that code doesn't do what they want to achieve. By the time the OnChange event is fired, the selection has already finished being changed to a new item and any chance of saving the modified data or canceling it has already passed. 

Share this post


Link to post

Indeed, the OnChanging event would be a better place. Unfortunately it is triggered at least twice when AllowChange is set to False, even with the checks shown above.

Share this post


Link to post
5 hours ago, Uwe Raabe said:

Indeed, the OnChanging event would be a better place. Unfortunately it is triggered at least twice when AllowChange is set to False, even with the checks shown above.

Yup. When I tested it, I got 3 events - 1) old item de-focused, then 2) old item de-selected, then 3) new item focused and selected together.

Share this post


Link to post

I realize a solution was found, but disabling the ListView when the user changes the contents of the Memo would ensure users remember to save or discard changes.

  • Like 1

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

×