Another way to go about this ...
without using a bool variable to prevent recursion ... is to use the ListView 'ItemCheck event which is a 'preview Event ... it's called before 'ItemChecked.
By "dis-connecting" the ItemCheck EventHandler when the 'SelectAll CheckBox has its CheckState changed, we can then go ahead and set all the CheckBoxes to that same state; then, we re-connect the ItemCheck EventHandler when we're done, so "normal" use is restored for all the other CheckBoxes.
private void listView1_ItemCheck(object sender, ItemCheckEventArgs e)
{
if (e.Index == 0)
{
bool isCheckAll = e.NewValue == CheckState.Checked;
listView1.SuspendLayout();
listView1.Items[0].Text = isCheckAll
? "Deselect All"
: "Select All";
listView1.ItemCheck -= listView1_ItemCheck;
for (int i = 1; i < listView1.Items.Count; i++)
{
listView1.Items[i].Checked = isCheckAll;
}
listView1.ItemCheck += listView1_ItemCheck;
listView1.ResumeLayout();
}
}
Notes:
1. there's nothing wrong doing this another way using a variable to prevent recursion !
2. the WinForm ListView is an old creature, and, you may notice, is inconsistent in structure and syntax compared to other Controls. Many other WinForm Controls have an equivalent to the 'ItemCheck Event of the ListView whose name starts with 'Before..., and those Event Handlers often have a built-in way to allow you to cancel the complementary 'After... Event Handler.
3. for production code: I would choose to keep track of the state of all the ListView Items (not the 'Select/DeSelect item) so that any time they were all either checked, or unchecked, the Text of the 'Select/DeSelect ListViewItem would reflect what its next CheckState will do. But, that's getting 'fancy: you implement that, your client/employer should pay you more :)