1

I am trying to create a new Thread and put it to sleep in some occasions, but when I do it the main thread sleep, not only the one that I had created. I am using a Dispatcher.BeginInvoke but this is only to "give a permission" from the main thread to access to the method.

It works because it does not give me an InvalidOperationException, but the "focus" of the created thread losses when the linked method start.

I think I should use a ManualResetEvent to wait for the created Thread, but I do not know how doing it. I have been looking for possible solutions but no one works.

I think this should be easy but i cannot do it. The following code is Below:

void EmpujeDispatcher(object objeto)
{
    this.Dispatcher.BeginInvoke(new Action<object>(Empuje), objeto);
}
private void Empuje(object objeto)
{
    Thread.Sleep(2000); MessageBox.Show("This should not freeze the window");

                Canvas Bacteria = objeto;
                double PosX = Canvas.GetLeft(Bacteria);//Posición del sender
                double PosY = Canvas.GetTop(Bacteria);//Lo mismo
                Bacterias BacteriaInstancia = InstanciaBacterias[Bacteria.Uid];//Se busca la bacteria para relacionarla con al instancia
                BacteriaInstancia.posX = PosX;
                BacteriaInstancia.posY = PosY;
                // BacteriaInstancia.Moverse();

                if (BacteriaInstancia.momemtum <= 0)
                {
                    Canvas.SetTop(Bacteria, PosY); Canvas.SetLeft(Bacteria, PosX);//Para el empuje
                    dispatcherTimer.Stop();
                }

                else
                {   //Rebote:
                    BacteriaInstancia.Posicion();
                    PosX = BacteriaInstancia.posX;
                    PosY = BacteriaInstancia.posY;
                    if (PosX + Bacteria.Width >= CanvasSimulador.Width) { BacteriaInstancia.direccionAnterior = BacteriaInstancia.direccion; BacteriaInstancia.direccion = 1; }
                    if (PosX <= 0) { BacteriaInstancia.direccionAnterior = BacteriaInstancia.direccion; BacteriaInstancia.direccion = 3; }
                    if (PosY + Bacteria.Height >= CanvasSimulador.Height) { PosY = CanvasSimulador.Height - Bacteria.Height; BacteriaInstancia.direccionAnterior = BacteriaInstancia.direccion; BacteriaInstancia.direccion = 2; }
                    if (PosY <= 0) { PosY = 1; BacteriaInstancia.direccionAnterior = BacteriaInstancia.direccion; BacteriaInstancia.direccion = 4; }
                    Canvas.SetTop(Bacteria, PosY); Canvas.SetLeft(Bacteria, PosX);

                    BacteriaInstancia.momemtum = Math.Sqrt(Math.Pow(BacteriaInstancia.Vfx, 2) + Math.Pow(BacteriaInstancia.Vfy, 2));
                    ControlFlujo = BacteriaInstancia.momemtum;




}
private void EmpujeEvent(object sender, MouseButtonEventArgs e)
{
    Thread TimerClockThread = new Thread(new ParameterizedThreadStart(EmpujeDispatcher));
    TimerClockThread.IsBackground = true;
    TimerClockThread.Start(sender);
}

This is not exacly the code because in this one Dispatcher does not have any sense, if I create the Thread without dispatcher

TimerClockThread = new Thread( new ParameterizedThreadStart(Empuje));

It works well... because it's a MessageBox, but in the original I have a lot of code inside of the "Empuje".

Thanks for your attention and hopefully you can help me :)

Enzo Zerega
  • 71
  • 1
  • 2
  • 8
  • I think I missed smth. Can you explain in which case there must be delay? and what do you mean talking "This should not freeze the window". which window? messagebox or which one? – Vasilii Ruzov Nov 12 '13 at 12:25
  • 1
    `Empuje` method runs on `Dispatcher` thread (UI/Main thread), since it was invoked via `Dispatcher.BeginInvoke` and with your call to `Thread.Sleep(2000)` you are essentially putting `Dispatcher` (UI/Main thread) to sleep. What is actual/original problem that you tried to solve this way? – Suresh Nov 12 '13 at 12:27
  • "This should not freeze the window"="This should not freeze main Thread", the Thread sleeped should be the TimerClockThread, not the main Thread. – Enzo Zerega Nov 12 '13 at 12:29
  • @EnzoZerega, calling Dispatcher.BeginInvoke() you obtain main thread and do all operation from the main thread. So you have to use another thread if you don't want delays – Vasilii Ruzov Nov 12 '13 at 12:34
  • I am trying to sleep the TimerClockThread, not the Main thread. If i create the Thread without Dispatcher: TimerClockThread = new Thread( new ParameterizedThreadStart(Empuje)); works if i use the Empuje method only with a MessageBox and ThreadSleep. But i need to do more stuff with that method (using backend) so i need the Dispatcher. – Enzo Zerega Nov 12 '13 at 12:36
  • @EnzoZerega. frankly speaking, I don't understand what you are talking about. Can you please explain clearly what behaviour do you expect from the code? step by step after creating thread and passing Empuje as parameter. – Vasilii Ruzov Nov 12 '13 at 12:41
  • I have a window with a main canvas and a lot of Littlecanvas with animated gifs inside. When i click one of those(EmpujeEvent), only the clicked element should sleep and stop moving. The image is in the backend so, if i create a thread directly with empuje give me an InvalidOperationException. I need to run the empuje method with TimerClockThread. – Enzo Zerega Nov 12 '13 at 12:59
  • @EnzoZerega, do you do some operations in thread to animate gifs? our you just insert it as an image? – Vasilii Ruzov Nov 12 '13 at 13:05
  • I update the code. If i use: TimerClockThread = new Thread( new ParameterizedThreadStart(Empuje)); give me an InvalidOperationException in the 3rd line double PosX = Canvas.GetLeft(Bacteria); I need to the TimerClockThread use that method without give me the exception. – Enzo Zerega Nov 12 '13 at 13:13
  • @EnzoZerega. Look. In code you've posted when you call Dispatcher.BeginInvoke you obtain the control on the UI thread. This is not the thread where only pressed gif is operating. This is MAIN UI thread. so if you call Thread.Sleep() you suspend this main ui thread. [look here](http://stackoverflow.com/questions/15647901/c-sharp-how-to-stop-animated-gif-from-continually-looping). – Vasilii Ruzov Nov 12 '13 at 13:31
  • Ok i understand, that was the problem. thanks! – Enzo Zerega Nov 12 '13 at 13:43

3 Answers3

3

Your Dispatcher.Invoke forces your Empuje method to be called on the UI thread. If you want to update the screen, you should move the call to the background thread:

TimerClockThread = new Thread( new ParameterizedThreadStart(Empuje));

private void Empuje(object objeto)
{
   Thread.Sleep(2000); 
   Dispatcher.BeginInvoke(new Action(() => {
       MessageBox.Show("This should not freeze the window");
   }));
   //........ Do stuff.....
}

In modern C# with async however, you can remove all code and instead write:

private async void EmpujeEvent(object sender, MouseButtonEventArgs e)
{
    await Task.Delay(2000);
    MessageBox.Show(...);
}
Bas
  • 26,772
  • 8
  • 53
  • 86
0

Your function EmpujeDispatcher is using the same dispatcher that your GUI thread is associated with. That means you are telling the dispatcher to execute Empuje asynchronously, unfortunately it is executed on the GUI thread. At least that's what I think.

o_weisman
  • 804
  • 7
  • 19
0

A BackgroundWorker is quite fit for this task. The shortest piece of code to implement it looks like this:

var worker = new BackgroundWorker();
worker.DoWork += (s,e) => 
{
    Thread.Sleep(2000);
    // Do Stuff...
};
worker.RunWorkerAsync();

Searching SO will yield a plethora of Q&A about the BackgroundWorker (i.e. this or this)

Community
  • 1
  • 1
Alex
  • 23,004
  • 4
  • 39
  • 73