3

我在 C# .NET 4.5 中使用多选 ListView 选择多个项目(即 Shift + End 或 Shift + Click 等)时会出现问题。这些只是用于多选的许多不同鼠标/键盘组合的几个示例当然..

这是我在列表中选择项目时的事件处理程序:

private void lvTitles_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
{
    MessageBox.Show(e.Item.Text.ToString());
    //MessageBox just for testing I am actually running a SQL query here
}

我的问题是,如果我选择 500 个项目,则事件会被触发 500 次。目的是获取用户选择的最后一个项目(通过上面提到的键盘/鼠标组合),并对其进行处理......在我的情况下,我需要对其运行 SQL 查询。

如果我首先单击列表视图中的第 0 项,则可以运行查询,然后当您 shift+end 时,它会突出显示所有其余部分,并且我希望它仅在最后选择的项目上运行查询。相反,它在其间的每个项目上运行。

编辑:另一方面,事件在取消选择时也会触发,在这种情况下,取消选择时它真的不应该做任何事情。

4

1 回答 1

1

您是否考虑过在按下按钮时执行该操作?这样他们也可以使用 Ctrl-Click 来选择他们想要的任何单个项目?

否则你必须做的是在触发动作之前等待一段时间,称为去抖动,你可以在这里阅读更多关于去抖动的信息:https ://stackoverflow.com/a/4517995/984780

我创建了一个可用于去抖动的类:

public class Debounce {
    private Action _action;
    private bool _isThreadRunning;
    private Thread _thread;
    private DateTime _runAt;
    private double _waitSeconds;

    private Debounce(double waitSeconds, Action action) {
        _action = action;
        _waitSeconds = waitSeconds;
    }

    private void Invoke() {
        _runAt = DateTime.Now.AddSeconds(_waitSeconds);

        lock(this) {
            if(!_isThreadRunning) {
                _isThreadRunning = true;

                _thread = new Thread(() => {
                    while(true) {
                        Thread.Sleep(100);

                        lock(this) {
                            if(DateTime.Now > _runAt) {
                                _action();
                                _isThreadRunning = false;
                                _thread = null;
                                break;
                            }
                        }
                    }
                });

                _thread.Start();
            }
        }
    }

    private static Dictionary<Action, Debounce> __debounces;
    private static Dictionary<Action, Debounce> _debounces {
        get {
            if(__debounces == null) {
                __debounces = new Dictionary<Action, Debounce>();
            }

            return __debounces;
        }
    }

    public static void Run(double waitSeconds, Action action) {
        Debounce debounce;

        if(!_debounces.TryGetValue(action, out debounce)) {
            debounce = new Debounce(waitSeconds, action);
            _debounces.Add(action, debounce);
        }

        debounce._waitSeconds = waitSeconds;
        debounce.Invoke();
    }
}

然后您可以将代码更改为:

private void lvTitles_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
{
    Debounce.Run(5, () => MessageBox.Show(e.Item.Text.ToString()));
}

无论他们如何选择项目,这都应该有效,它将在他们最后一次选择操作后 5 秒运行您的代码。

我刚刚写了这门课并做了一个快速测试,建议进行更彻底的测试。在任何情况下,希望它足以得到这个想法。

于 2013-09-28T02:35:19.373 回答