【问题标题】:avoid list view selected index changed firing twice避免列表视图选定的索引更改触发两次
【发布时间】:2012-09-18 03:41:02
【问题描述】:

很简单的问题,当列表视图的选定索引发生变化时,事件会触发两次,一次用于取消选择,第二次用于选择下一项。

我需要在不同时间选择或取消选择时使用该事件,但是如果取消选择只是稍后重新选择,它会使我的一半 ui 闪烁从启用到关闭再重新打开,这也会导致相当多的代码运行所以我只需要一种方法来避免取消触发,如果它是另一个被点击的项目而不是空格(用于取消选择)

Dave R 说在这里使用 100 毫秒计时器:Am I missing something with my ListView selection event handling 这听起来像是可行的,但似乎很不整洁,或者通常是一种不好的做法。

我唯一的另一个想法是使用点击事件,然后在该位置找到项目?但我宁愿不去麻烦

提前致谢!

-编辑-

我只是认为单击事件会首先触发,因此我可以设置一个标志,如果单击事件发生在项目上,则跳过选择索引更改的代码,然后在使用后重置标志,从而跳过取消选择?我现在去看看,但又觉得不是一种非常有效或简单的方法来做一些听起来很简单的事情?

【问题讨论】:

标签: vb.net winforms listview selectionchanged


【解决方案1】:

改用ItemSelectionChanged 事件 - ListViewItemSelectionChangedEventArgs 可以告诉您是哪个项目导致它触发,以及它是否被选中。

【讨论】:

    【解决方案2】:

    我刚刚尝试了另一种可能没有任何延迟的解决方案,它对我有用:

        If ListView1.Items(ListView1.FocusedItem.Index).Selected = False Then
            'This is the deselected value
            MsgBox("Deselected: " & ListView1.Items(ListView1.FocusedItem.Index).SubItems(0).Text)
        Else
            'This is the new selected value
            MsgBox("Selected: " & ListView1.Items(ListView1.FocusedItem.Index).SubItems(0).Text)
        End If
    

    【讨论】:

    • 您倒退了,但是是的(将 False 更改为 True),这是一个更好的解决方案。试图计时这个过程绝对是一场噩梦。不知道为什么会得到这么多赞成票。此解决方案也适用于 Compact Framework,因为 CF.NET 2.0 没有确定典型值所需的事件参数 - e.IsSelected。
    【解决方案3】:

    即使延迟 1 毫秒,以下解决方案也能正常工作。为了确保它可以正常工作,您可能可以选择更高的延迟,例如 10 毫秒,但是 100 毫秒的延迟会使选择“无”时有点滞后。这是 C# 代码:

    public class FixedListView : ListView
    {
        private Timer _ItemSelectionChangedTimer = new Timer();
        private Timer _SelectedIndexChangedTimer = new Timer();
    
        private ListViewItemSelectionChangedEventArgs _ItemSelectionChangedEventArgs;
        private EventArgs _SelectedIndexChangedEventArgs;
    
        public FixedListView()
        {
            this._ItemSelectionChangedTimer.Interval = 1;
            this._SelectedIndexChangedTimer.Interval = 1;
    
            this._ItemSelectionChangedTimer.Tick += (sender, e) =>
            {
                this.OnItemSelectionChanged(this._ItemSelectionChangedEventArgs);
                this._ItemSelectionChangedEventArgs = null;
            };
            this._SelectedIndexChangedTimer.Tick += (sender, e) =>
            {
                this.OnSelectedIndexChanged(this._SelectedIndexChangedEventArgs);
                this._SelectedIndexChangedEventArgs = null;
            };
        }
    
        protected override void OnItemSelectionChanged(ListViewItemSelectionChangedEventArgs e)
        {
            if (this._ItemSelectionChangedTimer.Enabled)
            {
                this._ItemSelectionChangedTimer.Stop();
                base.OnItemSelectionChanged(e);
            }
            else
            {
                this._ItemSelectionChangedEventArgs = e;
                this._ItemSelectionChangedTimer.Start();
            }
        }
    
        protected override void OnSelectedIndexChanged(EventArgs e)
        {
            if (this._SelectedIndexChangedTimer.Enabled)
            {
                this._SelectedIndexChangedTimer.Stop();
                base.OnSelectedIndexChanged(e);
            }
            else
            {
                this._SelectedIndexChangedEventArgs = e;
                this._SelectedIndexChangedTimer.Start();                
            }
        }
    }
    

    这是 VB 代码:

    Public Class FixedListBox
    
    Inherits ListView
    
    Public Sub New()
    
        Me._ItemSelectionChangedTimer.Interval = 1
        Me._SelectedIndexChangedTimer.Interval = 1
    
        AddHandler Me._ItemSelectionChangedTimer.Tick, _
            Sub(sender, e)
                Me.OnItemSelectionChanged(Me._ItemSelectionChangedEventArgs)
                Me._ItemSelectionChangedEventArgs = Nothing
            End Sub
    
        AddHandler Me._SelectedIndexChangedTimer.Tick, _
            Sub(sender, e)
                Me.OnSelectedIndexChanged(Me._SelectedIndexChangedEventArgs)
                Me._SelectedIndexChangedEventArgs = Nothing
            End Sub
    
    End Sub
    
    Private _ItemSelectionChangedTimer As New Timer()
    Private _SelectedIndexChangedTimer As New Timer()
    
    Private _ItemSelectionChangedEventArgs As ListViewItemSelectionChangedEventArgs
    Private _SelectedIndexChangedEventArgs As EventArgs
    
    Protected Overrides Sub OnItemSelectionChanged(e As ListViewItemSelectionChangedEventArgs)
    
        If Me._ItemSelectionChangedTimer.Enabled Then
    
            Me._ItemSelectionChangedTimer.Stop()
            MyBase.OnItemSelectionChanged(e)
    
        Else
    
            Me._ItemSelectionChangedEventArgs = e
            Me._ItemSelectionChangedTimer.Start()
    
        End If
    
    End Sub
    
    Protected Overrides Sub OnSelectedIndexChanged(e As EventArgs)
    
        If Me._SelectedIndexChangedTimer.Enabled Then
    
            Me._SelectedIndexChangedTimer.Stop()
            MyBase.OnSelectedIndexChanged(e)
    
        Else
    
            Me._SelectedIndexChangedEventArgs = e
            Me._SelectedIndexChangedTimer.Start()
    
        End If
    
    End Sub
    

    结束类

    您可以像使用普通 ListView 一样使用该控件,但 SelectedIndexChanged 和 ItemSelectionChanged 只会触发一次。

    玩得开心……

    【讨论】:

      【解决方案4】:

      只需在 SelectedIndexChanged 事件中检查焦点项是否为空并退出。

      ListView^ item = listView1-> FocusedItem;   //get selected item
      if (item == nullptr){return;)  // this line exits when deselection event fires
      String^ data1 = Convert::ToString (  item-> SubItems [0]    );   // get your data from columns like so
      MessageBox::Show (data1);  // display
      

      请注意,您可以通过更改 SubItems 中提供的索引来获取多个列下的数据 使用计时器和延迟只会产生开销,尤其是大型数据库会导致您的应用程序在 Visual C++ .NET 中减慢代码,但同样的理论适用于 C# 和其他人

      享受!!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多