【问题标题】:C# wpf dispatcher threadC# wpf 调度程序线程
【发布时间】:2013-11-12 12:16:28
【问题描述】:

我正在尝试创建一个新的Thread 并在某些情况下使其进入睡眠状态,但是当我这样做时,主线程睡眠,而不仅仅是我创建的那个。我正在使用Dispatcher.BeginInvoke,但这只是为了从主线程“授予权限”以访问该方法。

它之所以有效,是因为它没有给我InvalidOperationException,而是在链接方法启动时创建的线程的“焦点”丢失。

我想我应该使用ManualResetEvent 来等待创建的Thread,但我不知道该怎么做。我一直在寻找可能的解决方案,但没有一个可行。

我认为这应该很容易,但我做不到。以下代码如下:

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

这不是代码,因为如果我在没有调度程序的情况下创建线程,Dispatcher 没有任何意义

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

效果很好...因为它是MessageBox,但在原版中,我在“Empuje”中有很多代码。

感谢您的关注,希望您能帮助我:)

【问题讨论】:

  • 我想我错过了。你能解释一下在什么情况下必须延迟吗?你是什​​么意思说“这不应该冻结窗口”。哪个窗口?消息框还是哪个?
  • Empuje 方法在Dispatcher 线程(UI/主线程)上运行,因为它是通过Dispatcher.BeginInvoke 调用的,并且通过您对Thread.Sleep(2000) 的调用,您实际上是在将Dispatcher(UI /主线程)睡觉。您尝试以这种方式解决的实际/原始问题是什么?
  • "这不应该冻结窗口"="这不应该冻结主线程",休眠的线程应该是 TimerClockThread,而不是主线程。
  • @EnzoZerega,调用 Dispatcher.BeginInvoke() 获取主线程并从主线程执行所有操作。所以如果你不想延迟,你必须使用另一个线程
  • 我正在尝试休眠 TimerClockThread,而不是主线程。如果我在没有调度程序的情况下创建线程: TimerClockThread = new Thread(new ParameterizedThreadStart(Empuje));如果我仅将 Empuje 方法与 MessageBox 和 ThreadSleep 一起使用,则可以工作。但我需要用这种方法做更多的事情(使用后端)所以我需要调度程序。

标签: c# wpf multithreading dispatcher


【解决方案1】:

您的 Dispatcher.Invoke 强制您的 Empuje 方法在 UI 线程上被调用。如果你想更新屏幕,你应该把调用移到后台线程:

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.....
}

但是,在带有 async 的现代 C# 中,您可以删除所有代码并改为编写:

private async void EmpujeEvent(object sender, MouseButtonEventArgs e)
{
    await Task.Delay(2000);
    MessageBox.Show(...);
}

【讨论】:

    【解决方案2】:

    您的函数 EmpujeDispatcher 使用与您的 GUI 线程关联的相同调度程序。这意味着您告诉调度程序异步执行 Empuje,不幸的是它是在 GUI 线程上执行的。至少我是这么认为的。

    【讨论】:

      【解决方案3】:

      BackgroundWorker 非常适合这项任务。实现它的最短代码如下所示:

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

      搜索 SO 将产生大量关于 BackgroundWorker(即 thisthis)的问答

      【讨论】:

        猜你喜欢
        • 2013-02-07
        • 1970-01-01
        • 1970-01-01
        • 2014-03-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-02-25
        • 1970-01-01
        相关资源
        最近更新 更多