首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何避免数以千计不必要的ListView.SelectedIndexChanged事件?

如何避免数以千计不必要的ListView.SelectedIndexChanged事件?
EN

Stack Overflow用户
提问于 2008-09-17 19:38:42
回答 14查看 8.6K关注 0票数 17

如果用户选择了.NET 2.0 ListView中的所有项,则ListView将为每个项激发一个SelectedIndexChanged事件,而不是激发一个事件来指示选择已更改。

如果用户随后单击以仅选择列表中的一个项目,则对于取消选择的每个项目,ListView将触发一个SelectedIndexChanged事件,然后为单个新选择的项目触发一个SelectedIndexChanged事件,而不是触发一个事件以指示选择已更改。

如果您在SelectedIndexChanged事件处理程序中有代码,则当列表中开始有几百个/数千个项目时,程序将变得完全没有响应。

我已经考虑过驻留计时器,等等。

但是有没有人有一个好的解决方案来避免成千上万的不必要的ListView.SelectedIndexChange事件,而真正的one event就可以做到呢?

EN

回答 14

Stack Overflow用户

回答已采纳

发布于 2009-06-11 13:11:47

来自Ian的好解决方案。我把它变成了一个可重用的类,确保正确地处理计时器。我还缩短了获得响应更快的应用程序的时间间隔。此控件还使用双缓冲来减少闪烁。

代码语言:javascript
复制
  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());
     }
  }

如果可以改进的话,一定要让我知道。

票数 12
EN

Stack Overflow用户

发布于 2008-09-17 20:21:45

这就是我现在使用的dwell定时器解决方案(dwell的意思是“稍等片刻”)。这段代码可能会受到竞争条件的影响,也可能会出现空引用异常。

代码语言:javascript
复制
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
}
票数 3
EN

Stack Overflow用户

发布于 2014-01-15 19:25:19

我知道这是个老问题,但这似乎仍然是一个问题。

这是我不使用计时器的解决方案。

它在触发SelectionChanged事件之前等待MouseUp或KeyUp事件。如果您通过编程更改选择,那么这将不起作用,事件将不会触发,但您可以轻松地添加一个FinishedChanging事件或其他东西来触发事件。

(它还有一些东西可以阻止闪烁,这与这个问题无关)。

代码语言:javascript
复制
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);
    }
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/86793

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档