0

sorry if this is a silly question, I am new to C#, so please give me a break.

I am working on Revit API. currently, Revit API doesn't support multi-threading operations. my question is how to stop a loop without calling a new thread?

I am trying to get a snapshot and I am waiting for the user to pick a snap, so I put an infinite loop till the condition meets

while (!Clipboard.ContainsImage()) //loop till user get a clipboard image
                {

                }

but what if I want to abort this??? I have tried

private void Abort_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.KeyCode == Keys.Escape)
        {
            abort = true;
        }
    }

but this method requires threading ....any suggestions!!

M.Khalil
  • 33
  • 2
  • 7
  • 1
    You can use the `break` command to break out of the while loop. – Henk Jansen Jan 23 '14 at 08:49
  • 1
    Did you take a look at your cpu load with that `!Clipboard.ContainsImage()` That is not a good idea! – TGlatzer Jan 23 '14 at 08:49
  • 4
    Never **EVER** wait for a operation to be completed by using a `while` loop – RononDex Jan 23 '14 at 08:49
  • How about [Background Worker](http://msdn.microsoft.com/en-us/library/cc221403(v=vs.95).aspx)? – WiiMaxx Jan 23 '14 at 09:08
  • @RononDex why? Maybe I want to increment a progress bar every second while a task is running. Using a `while` in that instance makes perfect sense. – Gusdor Jan 24 '14 at 08:34
  • @Gusdor yes, when using something like `Thread.Sleep` it would make sense, however it is still a bad practise. A much better way would be to use events – RononDex Jan 24 '14 at 08:38
  • @RononDex if the requirement is "updating a progress bar every second", how do events help. It cannot be a cooperative update; you will need a `while(true){ UpdateProgress(); cancelToken.WaitHandle.Wait(1000); cancelToken.ThrowIfCancellationRequested(); }` – Gusdor Jan 24 '14 at 09:01
  • 1
    @Gusdor, you could use a Timer instead of a while loop for this. – RononDex Jan 24 '14 at 09:01
  • @RononDex but _why?_ All you get is more complicated code with callbacks and invokes flying around.. – Gusdor Jan 24 '14 at 09:03
  • @Gusdor Because that results in nicer / easier to read code. Furthermore the built-in timer should be much more error proof then a simple while loop. Also why reinvent the wheel and code it on your own? We are drifting a bit off-topic here. In the end it is a design philosophy and everyone handles this different. – RononDex Jan 24 '14 at 09:08
  • @RononDex you know what. I just implemented your `Timer` based solution while my task blocks on `CancellationToken.WaitHandle.WaitOne` and I tend to agree. The code is leaner. – Gusdor Jan 24 '14 at 12:52
  • @Gusdor what do you mean by ***my task blocks on*** and ***leaner*** ? – RononDex Jan 24 '14 at 12:56
  • @RononDex **learner**: less code, easier to read. **Blocks on**: I used the task cancellation waithandle (mutex) to wait for the duration (instead of loops and sleeps) and still observe cancellations. – Gusdor Jan 24 '14 at 13:00

1 Answers1

0

You want to look into asynchronous processing patterns in Revit - check for instance The Building Coders description of IExternalEvent.

It might take a little while to wrap your head around it, but let me try to explain:

Split your code up into two parts: The first part runs up until the moment you ask the user to pick a snap (I'm assuming this happens in another application?). In a separate thread, poll the clipboard (or register your application as a clipboard viewer) in your while loop. Don't forget to Sleep() while you're polling! As soon as your polling thread finds a picture, create an instance of an IExternalEvent subclass and post it to Revit. When Revit has some spare time, it will execute the Execute method, passing in a UIApplication that you can use to do the rest of your code.

Revit doesn't let you access it's API from multiple threads at the same time, but during the Execute method of an IExternalEvent subclass, you are guaranteed to be in the correct thread for running code.

You can also look into the OnIdling event - basically, this gets called each time Revit has some spare time too. So instead of using a while loop in a separate thread, you could just place your clipboard checking code in the event handler for the OnIdling event and create a mechanism (a flag) to tell you wether you are currently waiting for a snap or not...

Community
  • 1
  • 1
Daren Thomas
  • 67,947
  • 40
  • 154
  • 200