Question

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 :)

Was it helpful?

Solution

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(...);
}

OTHER TIPS

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.

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)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top