I need to enable or disable a button depending on whether at least a row is selected in the list or not.
Below is the code to reproduce this issue. The list is populated using the OnData event and it allows multiple rows to be selected.
I thought that I could use OnSelectItem to detect when the user changes the selection and then use the TListView SelCount function to detect the number of selected rows.
The problem is that SelCount returns 0 when the user selects multiple rows. This works fine if the list is populated manually (i.e. not through the OnData event).
Any ideas?
Thanks
Update: using the OnChange event instead seems to do the trick. Still it would be interesting to understand why SelCount returns 0 when multiple rows are selected (from within the SelectItem event).
Another Update: I posted a test project: https://dl.dropboxusercontent.com/u/35370420/TestListView2.zip as well as a screenshot:
To reproduce this issue run the app, select Item1, then SHIFT+Click on Item2. The button is disabled. My intention was to enable the button dynamically as long as there is at least one item selected in the list. If there is no selected item the button is disabled.
PAS file:
unit MainUnit;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ComCtrls, Vcl.StdCtrls;
type
TForm3 = class(TForm)
ListView1: TListView;
Button1: TButton;
procedure FormCreate(Sender: TObject);
procedure ListView1Data(Sender: TObject; Item: TListItem);
procedure ListView1SelectItem(Sender: TObject; Item: TListItem; Selected: Boolean);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form3: TForm3;
implementation
{$R *.dfm}
procedure TForm3.FormCreate(Sender: TObject);
begin
ListView1.Items.Count := 5;
end;
procedure TForm3.ListView1Data(Sender: TObject; Item: TListItem);
begin
Item.Caption := String.Format('Item%d', [Item.Index]);
end;
procedure TForm3.ListView1SelectItem(Sender: TObject; Item: TListItem; Selected: Boolean);
begin
Button1.Enabled := ListView1.SelCount > 0;
OutputDebugString(pchar(String.Format('SelCount = %d', [ListView1.SelCount])));
end;
end.
Form:
object Form3: TForm3
Left = 0
Top = 0
Caption = 'Form3'
ClientHeight = 600
ClientWidth = 952
Color = clBtnFace
DoubleBuffered = True
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
OnCreate = FormCreate
PixelsPerInch = 96
TextHeight = 13
object ListView1: TListView
Left = 168
Top = 160
Width = 250
Height = 150
Columns = <
item
AutoSize = True
Caption = 'Test'
end>
HideSelection = False
MultiSelect = True
OwnerData = True
TabOrder = 0
ViewStyle = vsReport
OnData = ListView1Data
OnSelectItem = ListView1SelectItem
end
object Button1: TButton
Left = 168
Top = 120
Width = 75
Height = 25
Caption = 'Some Action'
Enabled = False
TabOrder = 1
end
end
Ctrl+Click
works because it is updating individual items one at a time, and thus triggering individualOnSelectItem
events.Shift+Click
, on the other hand, can cause a different flow of events to be triggered (specifically,OnDataStateChange
), which you are not taking into account in virtual mode. This is not a bug in the underlying ListView control, it is by design to help optimize virtual mode usage by reporting state changes when a consecutive range of items change to the same state at the same time. – Whiff