Navaneeth K N
Navaneeth K N

Reputation: 15521

Delaying execution - C# WPF

I have a Grid control and clicking on each row does some background job to load the data. Each background job is performed on a thread pool thread. When user clicks on the items quickly, lot of requests to load data will be queued. I want to minimize this by providing a delay after clicking each row. There will be some delay before firing the request to load the data.

I am thinking about using DispatcherTimer class. Something like,

readonly DispatcherTimer dt = new DispatcherTimer();
private void Clicked(object sender, RoutedEventArgs e)
{
    dt.Interval = TimeSpan.FromSeconds(2);
    dt.Stop();
    dt.Start();
}

private void DtOnTick(object sender, EventArgs args)
{
    // Fire a thread and do data loading
}

Is this the correct way to approach the problem?

Any suggestions would be appreciated!

Upvotes: 0

Views: 1329

Answers (3)

Robert Rossney
Robert Rossney

Reputation: 96860

What you actually want to do is something like this:

private DateTime? _NextAllowedClick;

private void Clicked(object sender, RoutedEventArgs e)
{
   if (_NextAllowedClick != null && DateTime.Now < _NextAllowedClick)
   {
      return;
   }
   _NextAllowedClick = DateTime.Now + new TimeSpan(0, 0, 0, 2);
   ...
}

Upvotes: 0

Thorsten Dittmar
Thorsten Dittmar

Reputation: 56727

The way you're trying to do it would just delay the problem itself for 2 seconds. All the clicks would just be handled two seconds later.

You might try to use a worker thread. Lets say you use a queue which takes information about each item that was clicked at the time it was clicked. An existing thread, created when the class is created, is notified when new items are added to the queue. The thread takes the first item, processes it, updates the UI. If there are more items, it takes the next one, processes it, etc. When there are no more items, the thread goes to sleep until new items are available (ManualResetEvent will help here).

The pattern would be:

void ItemClicked(...) 
{
    lock (WorkQueue)
    {
        QueueNewClickItem(...);
        m_workToDo.Set();
    }
}


void WorkerThread(...)
{
    bool threadShouldEnd = false;
    while (!threadShouldEnd)
    {
        if (WaitHandle.WaitAny(m_workToDo, m_endThread) == 0)
        {
           lock (WorkQueue)
           {
               CopyAllPendingWorkItemsToListInThread();
               ClearWorkQueue();
               m_workToDo.Reset();
           }

           while (!AllLocalItemsProcessed)
           {
               ProcessNextWorkItem();
           }
        }
        else
        {
            threadShouldEnd = true;
        }
     }
 }

Upvotes: 1

JJ15k
JJ15k

Reputation: 93

How about disabling the control until the job is finished? Or disabling once the queue of jobs to do reaches a certain size? This would be a simple solution to prevent users from "clicking too much". And this way the delay would scale with the efficiency of your solution/speed of the computer.

Upvotes: 1

Related Questions