2017-01-31 3 views
7

У меня есть элемент управления, который позволяет пользователю выполнять некоторую обработку тяжелых изображений на определенной части изображения, и у них есть кнопки со стрелками для перемещения этой области вокруг изображения.Кнопка повтора Tapping

как процесс очень тяжелый (avg 800ms за один запуск) Я использовал кнопку повтора, которая превращает это в «Призрак» и выполняет этот процесс только при событии мыши.

Это работает очень хорошо, и решает большинство проблем производительности, связанные с этой функцией

ОДНАКО

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

Это означает, что метод тяжелого режима вызывается каждый раз, когда они нажимают, и когда он только движется с небольшим приращением каждый раз, когда срабатывает метод, поэтому они оказываются в зависании приложения, пока он пытается сделать> 100 из этих 800ms + процессы

МОЙ ВОПРОС

Как я могу справиться с этим выстукивая поведение таким же образом, как проведение и освобождение?

Я думал о таймере, но не могу понять, как бы я обнаружил разницу между нормальным краном и последним краном.

+6

У вас может быть только флаг 'bool', который вы установили в true при запуске процесса и false, когда он будет завершен. Если флаг имеет значение true, пусть событие кнопки возвращается раньше, не запуская процесс. – Abion47

+1

Вы можете использовать таймер, чтобы ждать, пока нет последовательных отводов в течение некоторого времени, чтобы начать тяжелую работу. Для серии кранов таймер будет перезапущен, а обработчик событий (содержащий тяжелую работу) не будет запущен. – Sinatr

+0

Abion47 посоветовал вам сделать это с флагом. Вы попробовали? –

ответ

2

Рассмотрите возможность мониторинга активности мыши и начните свой тяжелый процесс после короткого периода бездействия.

Рассмотрите возможность запуска процесса в отдельной ветке - это может означать клонирование (часть) изображения в памяти.

Рассмотрите возможность предотвращения одновременного запуска нескольких процессов (если это возможно, то есть процесс является асинхронным).

+1

Как правило, вы можете сделать «короткий период» 250-500 мсек, где-то там работает. Люди обычно могут нажимать кнопку 4-6 раз в секунду с легкостью. –

1

Как я могу справиться с этим постукиванием так же, как удерживать и отпускать?

Создать формулу, которая вычисляет веса значения частоты на основе последнего из-под краном, текущая операцию и время между последней фактической эксплуатацией; с любыми другими факторами Возможно, я не знаю. При правильной формуле он должен быть репрезентативным для человека, который правильно использует систему, для тех, кто посылает несколько кликов.

Весовое значение должно быть передано альтернативной нити, которая обрабатывает фактическую операцию на экране, и может обрабатывать метель кранов или один кран без пропусков, как таковой.

2

Рассмотрим один из этих вариантов:

Отключить кнопку, пока процесс не завершится, в результате чего, что 800ms задержки. Вскоре пользователи научатся использовать метод удержания. Это потребует наименьшего количества кода и наложит бремя на людей. Это также гарантирует, что вы не поддерживаете приложение с кликами в буфере или чрезмерным использованием ресурсов.

Поставьте таймер в вашем случае нажатия кнопки: «область привидения» Таймер Start (или обнулить)

Тогда код для вызова вашей основной работы в таймер истекшего событие, которое будет установлено в какую бы паузу вы ни пожелали. (То есть, если пользователь не нажал еще раз в течение секунды или около этого) Затем остановить таймер Выполнить код

2

Быстрый, грязный раствор: использовать Timer.

Каждый раз, когда пользователь нажимает кнопку, останавливает таймер, увеличивает количество кранов, запускает таймер. Если таймер истечет до того, как пользователь снова заработает, он должен выполнить свой большой метод работы.

Является ли это склонным к проблемам с резьбой?Возможно. Я не эксперт по теме. Мне бы очень хотелось, чтобы эксперт по потокам мог прокомментировать это.

Это лучшее решение?Вряд ли. Но это заставит вас некоторое время (пока не появятся проблемы с потоками).

private int _totalTaps = 0; 
private const int _tapSequenceThreshold = 250; // Milliseconds 
private Timer _tapTimer = new Timer(_tapSequenceThreshold); 

private void InitializeTimer() 
{ 
    _tapTimer.Elapsed += OnTapTimerElapsed; 
} 

private void OnTapTimerElapsed(object source, System.Timers.ElapsedEventArgs e) 
{ 
    _tapTimer.Stop(); 

    // The `DoBigLogic` method should take the number of taps and 
    // then do *something* based on that number, calculate how far 
    // to move it, for example. 
    DoBigLogic(_totalTaps); 

    _totalTaps = 0; 
} 

// Call this each time the user taps the button 
private void Tap() 
{ 
    _tapTimer.Stop(); 
    _totalTaps++; 
    _tapTimer.Start(); 
} 

Лучшее решение: этот метод плюс перемещении отрабатывают GUI потока. Тогда вам не нужно беспокоиться о кранах или щелчке и удержании, вы не будете делать блок поток GUI.

Если вам нужно выполнить работу, которая не обновляет пользовательский интерфейс (например, перерисовать изображение) затем отправить изображение в пользовательский интерфейс, вы можете создать новый поток, после чего вы получите сообщение об ошибке «доступ к элементу пользовательского интерфейса из потока, отличного от UI», просто отбросьте код UI в маршале для него.

await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(
    Windows.UI.Core.CoreDispatcherPriority.Normal, 
    () => { UpdateDisplay(); } 
); 
1

Вы можете попробовать использовать реактивные расширения which is available on nuget.

using System; 
using System.Windows.Controls; 
using System.Windows.Input; 
using System.Linq; 
using System.Reactive.Linq; 

namespace SmoothOutButtonTapping 
{ 
    public static class Filters 
    { 
     // First we need to combine the pressed events and the released 
     // events into a single unfiltered stream. 
     private static IObservable<MouseButtonState> GetUnfilteredStream(Button button) 
     { 
      var pressedUnfiltered = Observable.FromEventPattern<MouseButtonEventHandler, MouseButtonEventArgs>(
       x => button.PreviewMouseLeftButtonDown += x, 
       x => button.PreviewMouseLeftButtonDown -= x); 
      var releasedUnfiltered = Observable.FromEventPattern<MouseButtonEventHandler, MouseButtonEventArgs>(
       x => button.PreviewMouseLeftButtonUp += x, 
       x => button.PreviewMouseLeftButtonUp -= x); 

      return pressedUnfiltered 
       .Merge(releasedUnfiltered) 
       .Select(x => x.EventArgs.ButtonState); 
     } 

     // Now we need to apply some filters to the stream of events. 
     public static IObservable<MouseButtonState> FilterMouseStream(
      Button button, TimeSpan slidingTimeoutWindow) 
     { 
      var unfiltered = GetUnfilteredStream(button); 

      // Ironically, we have to separate the pressed and released events, even 
      // though we just combined them. 
      // This is because we need to apply a filter to throttle the released events, 
      // but we don't need to apply any filters to the pressed events. 
      var released = unfiltered 

       // Here we throttle the events so that we don't get a released event 
       // unless the button has been released for a bit. 
       .Throttle(slidingTimeoutWindow) 
       .Where(x => x == MouseButtonState.Released); 

      var pressed = unfiltered 
       .Where(x => x == MouseButtonState.Pressed); 

      // Now we combine the throttled stream of released events with the unmodified 
      // stream of pressed events. 
      return released.Merge(pressed); 
     } 
    } 
} 

Теперь у нас есть поток, который будет реагировать немедленно всякий раз, когда пользователь нажимает, но не будет срабатывать отпущенном событие, если кнопка не будет отпущена достаточно долго.

Вот пример того, как вы могли бы использовать вышеупомянутый метод. Этот пример просто меняет цвет элемента управления, когда кнопка находится в состоянии «Пресса», но вы можете легко делать все, что захотите.

using System; 
using System.Windows.Controls; 
using System.Windows.Input; 
using System.Windows.Media; 
using System.Reactive.Linq; 
using System.Threading; 

namespace SmoothOutButtonTapping 
{ 
    public partial class SmoothTapButtonControl : UserControl 
    { 
     public SmoothTapButtonControl() 
     { 
      InitializeComponent(); 

      _pressed = new SolidColorBrush(Colors.Lime); 
      _released = Background; 

      // Don't forget to call ObserveOn() to ensure your UI controls 
      // only get accessed from the UI thread. 
      Filters.FilterMouseStream(button, SlidingTimeoutWindow) 
       .ObserveOn(SynchronizationContext.Current) 
       .Subscribe(HandleClicked); 
     } 

     // This property indicates how long the button must wait before 
     // responding to being released. 
     // If the button is pressed again before this timeout window 
     // expires, it resets. 
     // This is handled for us automatically by Reactive Extensions. 
     public TimeSpan SlidingTimeoutWindow { get; set; } = TimeSpan.FromSeconds(.4); 

     private void HandleClicked(MouseButtonState state) 
     { 
      if (state == MouseButtonState.Pressed) 
       Background = _pressed; 
      else 
       Background = _released; 
     } 

     private Brush _pressed; 
     private Brush _released; 
    } 
} 

Вы можете найти полную версию приведенных выше примеров (файлы проекта и XAML включены) на my github.

2

Вы можете запретить программе выполнять вашу функцию 800 мс, установив простые флаги (предпочтительно тип bool).

Вам необходимо создать три события. One Mouse Down, одно событие Mouse Up и другое - это событие перемещения мыши на кнопке. Установите флаг false при объявлении. Когда вы нажмете кнопку, сделайте свой флаг истинным в событии Mouse Down. И когда вы поднимаете клик мыши, то есть событие Mouse Up делает ваш флаг ложным.

Простая иллюстрация кода.

bool click = false,run_process = true; 

mouseDown_event() 
{ 
    click = true; 
} 

mouseUp_event() 
{ 
    click = false; 
} 

mouseMove_event() 
{ 
    if(click == true && run_process == true) 
    { 
     click = false; 
     run_process = false; 
     //call your function 
    } 
} 
Смежные вопросы