Событие, когда кнопка удерживается нажатой в течение некоторого времени

Я моделирую портативное устройство с WPF и MVVM (viewmodel - это конечный автомат, view - это имитируемый пластиковый корпус с кнопками).

Жест, который включает и выключает устройство - это "длинный щелчок" в кнопке. Например, во время использования, если я нажимаю кнопку "ОК", он отображает некоторый экран, но если я УДЕРЖИВАЮ на нем нажатие более трех секунд, он должен (имитировать) выключить устройство.

Я заглянул в RepeatButton, с этими Delay а также Interval свойства, но те, кажется, стреляют одинаково Click событие. Что мне нужно, это уволить регулярно Click если я удерживаю кнопку менее трех секунд и запускаю другую, другую LongClick (возможно, один раз), если я буду держать его более трех секунд.

Как я могу сделать это, используя RepeatButton или даже обычную кнопку?

2 ответа

Один из способов сделать это - привязать события MouseDown и MouseUp. Используйте что-то вроде секундомера, который запускается на MouseDown, и проверьте, сколько времени прошло на MouseUp. Если это менее 3 секунд, выполните действие Click(). Если это более 3 секунд, выполните действие LongClick().

private void Button_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
    stopwatch = new Stopwatch();
    stopwatch.Start();
}

private void Button_PreviewMouseUp(object sender, MouseButtonEventArgs e)
{
    stopwatch.Stop();

    if (stopwatch.ElapsedMilliseconds >= 3000)
    {
         // do Click()
    }
    else
    {
        // do LongClick
    }
}

И вот решение для RepeatButton:

private bool isLongClick;
private bool hasAlreadyLongClicked;
private void RepeatButton_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
    isLongClick = false;
    hasAlreadyLongClicked = false;
    stopwatch = new Stopwatch();
    stopwatch.Start();
}

private void RepeatButton_Click(object sender, RoutedEventArgs e)
{
    if (!hasAlreadyLongClicked && stopwatch.ElapsedMilliseconds >= 3000)
    {
        hasAlreadyLongClicked = true;
        isLongClick = true;
        // do your LongClick action
    }
}

private void RepeatButton_PreviewMouseUp(object sender, MouseButtonEventArgs e)
{
    if (!isLongClick)
    {
        // do short click action
    }
}

Хитрость в том, что RepeatButton - это, по сути, просто кнопка, которая запускает Click на каждом интервале. Таким образом, если мы запускаем секундомер в PreviewMouseDown для кнопки, мы можем проверять истекшее время на секундомере каждый раз, когда срабатывает событие Click, и изменять наше действие в зависимости от результата.

После медитации на выходных я разработал следующее рабочее решение:

  1. Создайте два логических флага в ViewModel: ClickedShort а также ClickedLong;
  2. Связывание Command свойство на кнопке, через команду, чтобы OK метод на ViewModel;
  3. Команда ОК выглядит так:

    public void OK()
    {
        if (!ClickedShort)
        {
            HandleShortClick();
            ClickedShort = true;
        }
        else if (!ClickedLong)
        {
            HandleLongClick();
            ClickedLong = true;
        }
    }    
    
  4. Есть два флажка в XAML, с IsChecked свойства, связанные с логическими флагами. Это просто реле, так что я могу отправлять информацию из View в ViewModel через привязку:

        <CheckBox x:Name="ClickedShort" IsChecked="{Binding ClickedShort, Mode=OneWayToSource}" Visibility="Collapsed"/>
        <CheckBox x:Name="ClickedLong" IsChecked="{Binding ClickedLong, Mode=OneWayToSource}" Visibility="Collapsed"/>
    
  5. Есть MouseUp событие в кнопке ОК, чтобы сбросить эти флаги на ложь, когда я отпущу кнопку.

Другие вопросы по тегам