问题
I'm developing a smart device project using the Compact Framework.
I have a ListView
with several checkable ListViewItem
s: the property CheckBoxes
is true. I need to check only one ListViewItem
at time, so I subscribed the ItemCheck
event:
// I need to know the last item checked
private ListViewItem lastItemChecked;
private void listView_ItemCheck(object sender, ItemCheckEventArgs e)
{
if (lastItemChecked != null && lastItemChecked.Checked)
{
/* I need to do the following to prevent infinite recursion:
i.e. subscribe and then unsubscribe the ItemCheck event. */
listView.ItemCheck -= listView_ItemCheck;
lastItemChecked.Checked = false;
listView.ItemCheck += listView_ItemCheck;
}
lastItemChecked = listView.Items[e.Index];
}
Is there a better way to prevent the infinite recursion and thus the Stack Overflow
?
回答1:
Well, I think what might be better than juggling with the EventHandlers is checking if the lastItemCheck is a current item from the EventArgs. Like this:
// I need to know the last item checked
private ListViewItem lastItemChecked;
private void listView_ItemCheck(object sender, ItemCheckEventArgs e)
{
// if we have the lastItem set as checked, and it is different
// item than the one that fired the event, uncheck it
if (lastItemChecked != null && lastItemChecked.Checked
&& lastItemChecked != listView.Items[e.Index] )
{
// uncheck the last item and store the new one
lastItemChecked.Checked = false;
}
// store current item
lastItemChecked = listView.Items[e.Index];
}
I think that you'll agree, that re-assigning EventHandlers is a bit worse than simply checking the reference of the stored object.
回答2:
Here's a simpler approach that can be reused for multiple lists.
private void listView_ItemCheck(object sender, ItemCheckEventArgs e)
{
var listView = sender as ListView;
if (listView != null)
{
for (var i = 0; i < listView.CheckedItems.Count; i++)
{
listView.CheckedItems[i].Checked = false;
}
}
}
The ItemCheck event fires before the list item state changes, so no additional tests are required.
ItemCheck - Indicates that an item is about to have its checked state changed. The value is not updated until after the event occurs.
The other answers checking if the current item doesn't match the current item does nothing useful as the selection occurs after this event has completed so it doesn't matter if you set it to false.
lastItemChecked != listView.Items[e.Index]
回答3:
M Bak you forgot to disable Item check event before assign new value. And your code will uncheck last checked value too, because you use checked event. Also CheckedItems.Count will be changed after Checked value changed. Fixed solution is:
private void LstFirstPageBanner_ItemCheck(object sender, ItemCheckEventArgs e)
{
var listView = sender as ListView;
if (listView != null)
{
var checkedCount = listView.CheckedItems.Count;
listView.ItemCheck -= LstFirstPageBanner_ItemCheck;
for (var i = 0; i < checkedCount; i++)
{
listView.CheckedItems[i].Checked = false;
}
listView.ItemCheck += LstFirstPageBanner_ItemCheck;
}
}
回答4:
So many code and tricks...
listView.SelectionMode = System.Windows.Controls.SelectionMode.Single;
回答5:
private void listView1_ItemChecked(object sender, ItemCheckedEventArgs e)
{
listView1.ItemChecked -= listView1_ItemChecked;
foreach (var item in listView1.CheckedItems)
{
if (e.Item != item)
{
((ListViewItem)item).Checked = false;
}
}
listView1.ItemChecked += listView1_ItemChecked;
}
来源:https://stackoverflow.com/questions/13858565/check-only-one-listviewitem-at-time