【问题标题】:Prevent events from firing multiple times from single action防止事件从单个操作中多次触发
【发布时间】:2010-03-05 19:00:02
【问题描述】:

如何防止触发由单个操作触发的多个相同类型的事件?

例如,我有一个 ListView 包含一些项目。当我选择或取消选择所有项目时,每个项目都会触发一次 SelectedIndexChanged 事件。相反,我希望接收单个事件指示用户的操作(选择/取消选择项目),而不考虑项目的数量。

有什么办法可以做到吗?

【问题讨论】:

    标签: c# winforms events


    【解决方案1】:

    您无法更改 ListView 代码,并且对其进行子类化并不能提供很多选择。

    我建议您只需在代码中添加一个小延迟(200 毫秒或类似) - 即您只在上次更新后的一小段时间进行计算。比如:

    using System;
    using System.Windows.Forms;
    static class Program {
        [STAThread]
        static void Main() {
            Application.EnableVisualStyles();
            ListView list;
            TextBox txt;
            Timer tmr = new Timer();
            tmr.Interval = 200;
            Form form = new Form {
                Controls = {
                    (txt = new TextBox { Dock = DockStyle.Fill, Multiline = true}),
                    (list = new ListView { Dock = DockStyle.Right, View = View.List,
                       Items = { "abc", "def" , "ghi", "jkl", "mno" , "pqr"}})
                }
            };
            list.SelectedIndexChanged += delegate {
                tmr.Stop();
                tmr.Start();
            };
            tmr.Tick += delegate {
                tmr.Stop();
                txt.Text += "do work on " + list.SelectedItems.Count + " items"
                     + Environment.NewLine;
            };
            Application.Run(form);
        }
    }
    

    【讨论】:

    • 一个例子将不胜感激:)
    • 我明白了,但是这种方法不会阻止执行,而是推迟执行。我正在寻找的是执行一次并放弃所有进一步不必要的执行。一旦选择或取消选择某些内容,我就会更新一个变量,该变量包含选择的整体状态,每个用户操作都需要执行一次。
    • 您必须放弃 earlier 操作 - 否则您不知道您对正确数据的操作。所示代码删除了除最后一个之外的所有内容。因此,它确实每个用户操作只执行一次。
    【解决方案2】:

    只有从稍微不同的方向来解决问题。例如。订阅失去焦点。

    最后,应用程序或运行时无法在“所有选择更改完成”时引发事件,而无需实际使用其他东西,因为应用程序无法预测用户是否会在控件保留时再次单击该控件重点。

    即使使用焦点,用户也可以切换回该控件。

    【讨论】:

    • 在 ListView 的背景中单击即可取消选择所有项目,但是对于每个取消选择的项目都会触发该事件,这会导致性能不佳,因为计算应该只发生一次为每个项目执行选择/取消选择,而不是选择更改。
    • @Michael:为什么不订阅点击事件,并在点击事件中读取当前选中项的集合?
    • 好主意,我试过了,它的性能非常好。唯一的缺点是,当您单击 ListView 的背景时,不会触发 Click 事件,这意味着我必须找到另一种方法来清除另一个视图。也许我会把清除的东西留在 SelectedIndexChanged 事件中。
    • 嗯,这也不好,因为在取消选择项目时也需要调用性能关键方法调用,所以我不能在点击事件处理程序中调用它。
    【解决方案3】:

    如果您的 ListViewvirtual mode 中,您可以使用 VirtualItemsSelectionRangeChanged event。对于用户的操作(选择/取消选择),该事件只会触发一次。

    【讨论】:

    • 虚拟模式需要什么?从来没有真正听说过这个。在 MSDN 上,它声明“为了使用虚拟模式,您必须处理 RetrieveVirtualItem 事件 (...)”。我是否必须为虚拟 ListView 提供其他功能才能像我习惯的非虚拟 ListView 一样工作?
    • “虚拟模式”意味着 ListViewItems 不是立即为所有项目创建的,而是按需创建的,仅为当前可见的项目创建。如果您有大量数据需要显示,并且如果您将数据存储在应用程序中除 ListView 之外的其他位置,则虚拟模式特别有用。所以基本上这两个区别是您自己存储项目的数据,并处理 RetrieveVirtualItem 事件。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-22
    • 1970-01-01
    • 1970-01-01
    • 2015-03-18
    • 1970-01-01
    相关资源
    最近更新 更多