Обработка как щелчка, так и двойного щелчка с помощью Reactive.ЧИСТЫЙ RX

#c# #.net #observable #system.reactive

Вопрос:

У меня есть кнопка WPF в .NET, и я хочу обрабатывать события щелчка и двойного щелчка отдельно. В настоящее время я работаю над этим, используя тайм-ауты/задержки, и это работает, но это некрасиво. Я пытаюсь найти простой способ сделать это с помощью системы.Реактивные расширения для .NET

Наблюдаемые объекты создаются из заводского метода, в котором я передаю кнопку, и я использую метод FromEventPattern(кнопка, «щелчок»). например:

     public IObservable<EventPattern<RoutedEventArgs>> SingleClickTestObservable(Button button)
    {
        return Observable.FromEventPattern<RoutedEventArgs>(button, "Click");
    }

    public IObservable<EventPattern<RoutedEventArgs>> DoubleClickTestObservable(Button button)
    {
        return Observable.FromEventPattern<RoutedEventArgs>(button, "DoubleClick");
    }
 

Проблема в том, что когда я подписываюсь на эти наблюдаемые, срабатывает одиночный щелчок как для одного, так и для двойного щелчка.

Как сделать так, чтобы это работало по назначению, чтобы при двойном щелчке срабатывал одиночный щелчок, а не один.

Ответ №1:

Решение, которое я придумал, заключается в привязке к событиям щелчка мыши в обоих примерах и размещении событий в буфере 350ms. А затем отфильтруйте на основе числа событий, произошедших за период времени 350 мс.

Для события с одним щелчком мы ожидаем, что в буфере будет событие с одним щелчком, а для события с двойным щелчком мы ожидаем, что будет ровно 2:

     public IObservable<EventPattern<RoutedEventArgs>> DoubleClickTestObservable(Button button)
    {
        var observable = Observable.FromEventPattern<RoutedEventArgs>(button, "Click");
        var bufferedObservable = observable.Buffer(observable.Throttle(TimeSpan.FromMilliseconds(350)))
            .Select(list => new { list.Count, list })
            .Where(result => result.Count == 2)
            .Select(x => x.list.Last());
        return bufferedObservable;

    }

    public IObservable<EventPattern<RoutedEventArgs>> SingleClickTestObservable(Button button)
    {
        var observable = Observable.FromEventPattern<RoutedEventArgs>(button, "Click");
        var bufferedObservable = observable.Buffer(observable.Throttle(TimeSpan.FromMilliseconds(350)))
            .Select(list => new { list.Count, list })
            .Where(result => result.Count == 1)
            .Select(x => x.list.Single());
        return bufferedObservable;
    }
 

Использование:

 var button = GetMyButton();         
var singleClickSub = DoubleClickTestObservable(button)
    .Subscribe(pattern => { _logger.Debug("got double click"); });
var doubleClickSub = SingleClickTestObservable(button)
    .Subscribe(pattern => { _logger.Debug("got single click"); });
 

Примечание: _logger-это мой собственный класс, замените его предупреждением или другим методом вывода для тестирования.

Комментарии:

1. Я бы предложил добавить a .Publish(xs => xs.Buffer(() => xs.Throttle(TimeSpan.FromMilliseconds(350.0)))) , чтобы предотвратить возможность нескольких подписок на ваш источник.