在wpf的线程中打开的窗口有多近?

时间:2014-04-29 15:40:19

标签: c# wpf multithreading

通过规范,我构建了一个监视某些资源的应用程序。现在我有一个主窗口,当事件发生时抛出一个警告,规范必须是一个明亮的颜色的大窗口。 我按如下方式解决了这个问题

 private void StatusChanges(Alarm m, EventArgs e)
        {

            //Compares two 32-bit signed integers for equality and, if they are equal, replaces one of the values.
                if (Interlocked.CompareExchange(ref running, 1, 0) == 0)
                {
                    newWindowThread = new Thread(new ThreadStart(() =>
                                                                     {

                        try
                        {
                            // Create and show the Window
                            Alert tempWindow = new Alert();

                            tempWindow.Show();
                            //if (cancelRun)
                            //    tempWindow.Close();

                            // Start the Dispatcher Processing
                            System.Windows.Threading.Dispatcher.Run();



                        }
                        catch (Exception)
                        {

                            throw;
                        }
                        finally
                        {
                            running = 0;

                        }

                    }));

                    // Set the apartment state
                    newWindowThread.SetApartmentState(ApartmentState.STA);

                    // Make the thread a background thread
                    newWindowThread.IsBackground = true;

                    newWindowThread.Start();

                }


            }
            else
            {


                if (Interlocked.CompareExchange(ref running, 0, 1) == 1)
                {
                    try
                    {
                        System.Windows.Threading.Dispatcher.FromThread(newWindowThread).InvokeShutdown();
                        Alert tempWindow = new Alert();
                        tempWindow.Close();
                    }
                    catch (Exception)
                    {

                        //throw;
                        MessageBox.Show("Todo esta ok");
                    }

                }

                //running = 0;
            }
        }

此方法由计时器

间隔执行

我的目标是当闹钟结束删除警报窗口的过程时,我使用了Thread.Abort();没有工作,有时程序抛出一个例外并且没有在外面发现任何视觉工作室,尝试使用threa.Join ();但它没有工作,直到

System.Windows.Threading.Dispatcher.FromThread use (newWindowThread) InvokeShutdown ().; 

这至少停止了窗口的显示,但是当我创建

Alert tempWindow = new Alert(); 

在initialize构造函数中

SoundPlayer player = new Sound ("../../Sounds/BOMB_SIREN-BOMB_SIREN-247265934.wav");
  player.PlayLooping();

当我关闭窗口时

player.Stop();

如果没有,我会做下一个

 Alert tempWindow = new Alert();
                        tempWindow.Close();

声音继续播放

我知道这不是最好的解决方案,但它确实有效。 我想提出你的意见,并就如何改进代码向我提出建议。

2 个答案:

答案 0 :(得分:2)

这个想法是从一个线程开始使用UI。因此,不是简单地创建一个全新的调度程序,为什么不简单地将新的窗口逻辑分配给现有的UI线程(毕竟,定时器已经在UI线程上自行完成了吗?)。

为什么要在新线程中启动新窗口?你有什么希望通过那个来完成的?

您的密切代码没有意义:

Dispatcher.FromThread(newWindowThread).InvokeShutdown();
Alert tempWindow = new Alert();
tempWindow.Close();

让我们来看看这个。首先,关闭第二个UI线程的调度程序。这意味着流向窗口的所有消息都不会消失。

然后,在原始UI线程上创建一个 new 窗口,然后关闭它。那应该完成的是什么?您想要关闭之前打开过的窗口,而不是新窗口!

在实践中,您需要保留对您已打开的原始窗口的引用 - 对它的引用并不重要。现在,如果你真的想继续使用你的双UI线程方法,那么你可以这样做:

alertWindow.Dispatcher.Invoke(alertWindow.Close);

这将告诉(已打开的)警报窗口上的消息循环,以便尽快关闭窗口。

有了这个,你的代码就会出现太多错误。首先,您使用过低级别的操作(Interlocked.CompareExchange来维护警报/没有警报逻辑?)。第二,你的评论完全无用 - 你只是说下一行的内容,字面意思 - 这没有用。而不是

// Compares two 32-bit signed integers for equality and, 
// if they are equal, replaces one of the values.

您希望使用描述您尝试实现的内容的内容,而不是 以及

// If we're the first ones to attempt to change the running flag,
// we'll create a new alert window.

请注意,该评论也很好地表明您正在做一些非常奇怪的事情。

三,你不必要地创建线程(更重要的是,UI线程 - 除了非常具体的情况之外,实际上应该只有一个)。没有理由在新线程中创建新窗口。你为什么这样做?

四,您的异常处理也不是很有帮助。例如,如果你所做的只是重新抛出异常,你可以省略catch子句 - 你可以单独使用try ... finally。更重要的是,异常将传播到新线程,而不是旧线程 - 这很可能会导致应用程序完全崩溃。

答案 1 :(得分:2)

快速查看代码,你正在做的就是关闭temp。窗口不正确。当您想要关闭现有窗口时,您正在创建一个全新的窗口。 这应该更新,以便保存现有的临时窗口,以便稍后可以关闭相同的实例。

我还更新了临时窗口的关闭,以便在关闭后关闭线程。

我更新了代码如下:

Alert _tempWindow;

private void StatusChanges(Alarm m, EventArgs e)
{
    //Compares two 32-bit signed integers for equality and, if they are equal, replaces one of the values.
        if (Interlocked.CompareExchange(ref running, 1, 0) == 0)
        {
            newWindowThread = new Thread(new ThreadStart(() =>
            {
                try
                {   
                    // Create and show the Window
                    _tempWindow = new Alert();
                    _tempWindow.Close += OnTempClosed;
                    _tempWindow.Show();

                    System.Windows.Threading.Dispatcher.Run();
                }
                catch (Exception)
                {
                    throw;
                }
                finally
                {
                    running = 0;
                }

            }));

            // Set the apartment state
            newWindowThread.SetApartmentState(ApartmentState.STA);
            // Make the thread a background thread
            newWindowThread.IsBackground = true;
            newWindowThread.Start();
        }
    }
    else
    {
        if (Interlocked.CompareExchange(ref running, 0, 1) == 1)
        {
            try
            {
                _tempWindow.Dispatcher.BeginInvoke((Action)_tempWindow.Close);
            }
            catch (Exception)
            {
                //throw;
                MessageBox.Show("Todo esta ok");
            }
        }
        //running = 0;
    }
}

private void OnTempClosed(object sender, EventArgs e)
{
    System.Windows.Threading.Dispatcher.FromThread(newWindowThread).InvokeShutdown();
}