如果用户选择了.NET 2.0 ListView中的所有项,则ListView将为每个项激发一个SelectedIndexChanged事件,而不是激发一个事件来指示选择已更改。
如果用户随后单击以仅选择列表中的一个项目,则对于取消选择的每个项目,ListView将触发一个SelectedIndexChanged事件,然后为单个新选择的项目触发一个SelectedIndexChanged事件,而不是触发一个事件以指示选择已更改。
如果您在SelectedIndexChanged事件处理程序中有代码,则当列表中开始有几百个/数千个项目时,程序将变得完全没有响应。
我已经考虑过驻留计时器,等等。
但是有没有人有一个好的解决方案来避免成千上万的不必要的ListView.SelectedIndexChange事件,而真正的one event就可以做到呢?
发布于 2009-06-11 13:11:47
来自Ian的好解决方案。我把它变成了一个可重用的类,确保正确地处理计时器。我还缩短了获得响应更快的应用程序的时间间隔。此控件还使用双缓冲来减少闪烁。
public class DoublebufferedListView : System.Windows.Forms.ListView
{
private Timer m_changeDelayTimer = null;
public DoublebufferedListView()
: base()
{
// Set common properties for our listviews
if (!SystemInformation.TerminalServerSession)
{
DoubleBuffered = true;
SetStyle(ControlStyles.ResizeRedraw, true);
}
}
/// <summary>
/// Make sure to properly dispose of the timer
/// </summary>
/// <param name="disposing"></param>
protected override void Dispose(bool disposing)
{
if (disposing && m_changeDelayTimer != null)
{
m_changeDelayTimer.Tick -= ChangeDelayTimerTick;
m_changeDelayTimer.Dispose();
}
base.Dispose(disposing);
}
/// <summary>
/// Hack to avoid lots of unnecessary change events by marshaling with a timer:
/// http://stackoverflow.com/questions/86793/how-to-avoid-thousands-of-needless-listview-selectedindexchanged-events
/// </summary>
/// <param name="e"></param>
protected override void OnSelectedIndexChanged(EventArgs e)
{
if (m_changeDelayTimer == null)
{
m_changeDelayTimer = new Timer();
m_changeDelayTimer.Tick += ChangeDelayTimerTick;
m_changeDelayTimer.Interval = 40;
}
// When a new SelectedIndexChanged event arrives, disable, then enable the
// timer, effectively resetting it, so that after the last one in a batch
// arrives, there is at least 40 ms before we react, plenty of time
// to wait any other selection events in the same batch.
m_changeDelayTimer.Enabled = false;
m_changeDelayTimer.Enabled = true;
}
private void ChangeDelayTimerTick(object sender, EventArgs e)
{
m_changeDelayTimer.Enabled = false;
base.OnSelectedIndexChanged(new EventArgs());
}
}
如果可以改进的话,一定要让我知道。
发布于 2008-09-17 20:21:45
这就是我现在使用的dwell定时器解决方案(dwell的意思是“稍等片刻”)。这段代码可能会受到竞争条件的影响,也可能会出现空引用异常。
Timer changeDelayTimer = null;
private void lvResults_SelectedIndexChanged(object sender, EventArgs e)
{
if (this.changeDelayTimer == null)
{
this.changeDelayTimer = new Timer();
this.changeDelayTimer.Tick += ChangeDelayTimerTick;
this.changeDelayTimer.Interval = 200; //200ms is what Explorer uses
}
this.changeDelayTimer.Enabled = false;
this.changeDelayTimer.Enabled = true;
}
private void ChangeDelayTimerTick(object sender, EventArgs e)
{
this.changeDelayTimer.Enabled = false;
this.changeDelayTimer.Dispose();
this.changeDelayTimer = null;
//Add original SelectedIndexChanged event handler code here
//todo
}
发布于 2014-01-15 19:25:19
我知道这是个老问题,但这似乎仍然是一个问题。
这是我不使用计时器的解决方案。
它在触发SelectionChanged事件之前等待MouseUp或KeyUp事件。如果您通过编程更改选择,那么这将不起作用,事件将不会触发,但您可以轻松地添加一个FinishedChanging事件或其他东西来触发事件。
(它还有一些东西可以阻止闪烁,这与这个问题无关)。
public class ListViewNF : ListView
{
bool SelectedIndexChanging = false;
public ListViewNF()
{
this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.EnableNotifyMessage, true);
}
protected override void OnNotifyMessage(Message m)
{
if(m.Msg != 0x14)
base.OnNotifyMessage(m);
}
protected override void OnSelectedIndexChanged(EventArgs e)
{
SelectedIndexChanging = true;
//base.OnSelectedIndexChanged(e);
}
protected override void OnMouseUp(MouseEventArgs e)
{
if (SelectedIndexChanging)
{
base.OnSelectedIndexChanged(EventArgs.Empty);
SelectedIndexChanging = false;
}
base.OnMouseUp(e);
}
protected override void OnKeyUp(KeyEventArgs e)
{
if (SelectedIndexChanging)
{
base.OnSelectedIndexChanged(EventArgs.Empty);
SelectedIndexChanging = false;
}
base.OnKeyUp(e);
}
}
https://stackoverflow.com/questions/86793
复制相似问题