问题
I am using the events ItemSelectionChanged
and SelectedIndexChanged
of the ListView class to answer this question.
The code is below, and the only bug that seems to remain is that I use the 250ms timer also when the user uses rubberband selection, not only for single or double click selection.
internal Form1()
{
InitializeComponent();
t.Tick += T_Tick;
}
internal bool santinela = false;
internal void T_Tick(object sender, EventArgs e)
{
t.Stop();
if (!santinela)
{
bool newVal = selectionChangedItem.Selected;
selectionChangedItem.Checked =
selectionChangedItem.Selected = newVal;
santinela = true;
}
}
internal Timer t = new Timer()
{
Interval = 250
};
internal bool santinela3 = true;
internal void listView1_ItemCheck(object sender, ItemCheckEventArgs e)
{
if (santinela3)
{
if (e.CurrentValue == CheckState.Checked)
{
listView1.SelectedIndices.Remove(e.Index);
}
else if (e.CurrentValue == CheckState.Unchecked)
{
listView1.SelectedIndices.Add(e.Index);
}
}
}
internal void listView1_ItemActivate(object sender, EventArgs e)
{
if (listView1.SelectedItems.Count > 0)
{
MessageBox.Show(listView1.SelectedItems[0].Text);
}
}
internal ListViewItem selectionChangedItem = null;
internal bool santinela2 = true;
internal void listView1_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
{
if (!santinela2)
{
return;
}
if (t.Enabled)
{
santinela = true;
t.Stop();
// double click: both clicks must be done in the same place
if (e.Item == selectionChangedItem)
{
if (!e.IsSelected)
{
santinela2 = true;
e.Item.Selected = true;
santinela2 = false;
}
listView1_ItemActivate(sender, EventArgs.Empty);
}
selectionChangedItem = null;
}
else
{
santinela = false;
t.Stop();
selectionChangedItem = e.Item;
t.Start();
}
}
internal void listView1_SelectedIndexChanged(object sender, EventArgs e)
{
if (listView1.SelectedIndices.Count == 0)
{
santinela = true;
t.Stop();
selectionChangedItem = null;
santinela3 = false;
for (int i = 0; i < listView1.CheckedItems.Count; ++i)
{
listView1.CheckedItems[i].Checked = false;
}
santinela3 = true;
}
}
The relevant designer code is below:
System.Windows.Forms.ListViewItem listViewItem1 = new System.Windows.Forms.ListViewItem("item1");
System.Windows.Forms.ListViewItem listViewItem2 = new System.Windows.Forms.ListViewItem("item2");
this.listView1 = new System.Windows.Forms.ListView();
this.SuspendLayout();
//
// listView1
//
this.listView1.CheckBoxes = true;
listViewItem1.StateImageIndex = 0;
listViewItem2.StateImageIndex = 0;
this.listView1.Items.AddRange(new System.Windows.Forms.ListViewItem[] {
listViewItem1,
listViewItem2});
this.listView1.Location = new System.Drawing.Point(12, 12);
this.listView1.Name = "listView1";
this.listView1.Size = new System.Drawing.Size(401, 327);
this.listView1.TabIndex = 0;
this.listView1.UseCompatibleStateImageBehavior = false;
this.listView1.ItemActivate += new System.EventHandler(this.listView1_ItemActivate);
this.listView1.ItemCheck += new System.Windows.Forms.ItemCheckEventHandler(this.listView1_ItemCheck);
this.listView1.ItemSelectionChanged += new System.Windows.Forms.ListViewItemSelectionChangedEventHandler(this.listView1_ItemSelectionChanged);
this.listView1.SelectedIndexChanged += new System.EventHandler(this.listView1_SelectedIndexChanged);
Update: The issue I am facing because of the timer is that after hovering with the rubberband a ListViewItem, there is the useless delay of the timer before the item gets checked. When the user resizes/moves the rubberband so that the ListViewItem is no longer checked, there is the same delay. If the user does not know of that non-standard delay, the selection can be wrong.
来源:https://stackoverflow.com/questions/54237368/how-can-i-find-if-a-selection-is-inside-the-rubberband-selection-in-a-listview