0

My Aim: I am having a credit card wait window. I will call a function from the client to wait for the credit card swipe. In order to avoid the program getting stuck while waiting for the credit card . I am using a delegate to run a timer. The delegate will call a timer. The timer periodically checks for the presence for the card. If it found a card it will a callback/delegate assigned by the client.

the code is given below, my questions are 1) Will the _timer_Elapsed will get called within the thread so that it will add minimum overhead to the ui window?

2) How can i call the callback/event of the base class from the timer function. I have written a protected method which will call the event/delegate in the base class. I need to call the protected method from the timer function( which is inside a delegate in the derived class.)?

Wait wait = delegate()
{

    _timer = new Timer(3000); // Set up the timer for 3 seconds

    _timer.Elapsed += new ElapsedEventHandler(_timer_Elapsed);
    _timer.Enabled = true; // Enable it
    static void _timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        // if(CheckCardsPresence())
        {
            //RaiseEvent()
            //KillTimer()
        }
        //else
        {
            // do nothing. wait more
        }

    }

};

wait.Invoke();

3 Answers 3

1

No, the timer callback will not execute on the delegate-thread.

  1. How could it? A timer cannot 'break in' on a thread, that thread has to poll.
  2. This delegate-thread will terminate immediately after starting the timer. Which means you don't need this thread at all. Unless there is code not shown.

When you use a System.Threading.Timer the callback will be pushed onto the Threadpool.

To the second question (do try to ask only 1 question at a time)

  • A protected member should be accessible from an anonymous (embedded) method. Do you have a concrete problem?
Sign up to request clarification or add additional context in comments.

Comments

0

From the MSDN documentation (sorry I got the wrong class the first time around)

This Windows timer is designed for a single-threaded environment where UI threads are used to perform processing. It requires that the user code have a UI message pump available.

This is a roundabout way of saying that the event will be raised on the UI thread / message pump, i.e. the answer to your first question is yes as long as by "the thread" you mean "the UI thread".

I don't really understand your second question - what base class are you talking about?

4 Comments

I think the Timer in the question is a WinForms Timer.
the delegate is called from a class which have a base class. the base class have a event which can be assigned by consumers of the client.
@Henk Actually we are both wrong - its the one from System.Timers
@logeeks: Your descriptions don't help much. Add an outline in C# to the question.
0

First, that code will not compile. You cannot declare a named method from within another method. You can, however, declare an anonymous method or lambda expression and then assign it to a delegate reference.

There may not be any need to do asynchronous polling of the credit card device. You might be able to use a System.Windows.Forms.Timer and perform the polling from the Tick event which runs on the UI thread. This would be acceptable if the CheckCardsPresence is a quick operation.

public class CreditCardWaitWindow : Form
{
  private System.Windows.Timer timer = new System.Windows.Timer();

  private void Form_Load(object sender, EventArgs args)
  {
    timer.Tick += OnTick;
    timer.Interval = 3000;
    timer.Start();
  }

  private void OnTick(object sender, EventArgs args)
  {
    if (CheckCardsPresence())
    {
      RaiseEvent();
      timer.Stop();
    }
  }
}

If polling the credit card device is a time consuming operation then you will want to perform this operation on another thread to avoid blocking the UI.

public class CreditCardWaitWindow : Form
{
  private System.Timers.Timer timer = new System.Timers.Timer();

  private void Form_Load(object sender, EventArgs args)
  {
    timer.Elapsed += OnElapsed;
    timer.Interval = 3000;
    timer.AutoReset = false;
    timer.Start();
  }

  private void OnElapsed(object sender, ElapsedEventArgs args)
  {
    if (CheckCardsPresence())
    {
      Invoke(
        (MethodInvoker)(() =>
        {
          RaiseEvent();
        }), null);
    }
    else
    {
      timer.Start();
    }
  }
}

Here is a cleaner implementation using a Task.

public class CreditCardWaitWindow : Form
{
  private void Form_Load(object sender, EventArgs args)
  {
    Task.Factory.StartNew(
      () =>
      {
        while (true)
        {
          Thread.Sleep(3000);
          if (CheckCardsPresence()) break;
        }
      }, TaskCreationOptions.LongRunning).ContinueWith(
      () =>
      {
        RaiseEvent();
      }, TaskScheduler.FromCurrentSychronizationContext());
  }    
}

And to really top things off you could do this in C# 5.01 with the new await keyword. I am not sure it can get anymore succinct than that!

public class CreditCardWaitWindow : Form
{
  private async void Form_Load(object sender, EventArgs args)
  {
    while (!CheckCardsPresence()) await Task.Delay(3000);
    RaiseEvent();
  }
}

1C# 5.0 has not been released yet.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.