单实例表单但不是单例

时间:2008-11-06 20:20:12

标签: c# winforms multithreading

我无法理解这是怎么回事。请帮忙!!

我有一个带有trayicon的应用程序。我希望在用户双击trayicon时显示一个表单。我有一个问题,可以通过快速三次或四次点击trayicon来显示2个或更多表格。我不想要单例的原因是我希望每次关闭表单时都要释放它以节省内存,这可能不是一个好主意吗?

我有一个名为m_form1的字段。 我有一个名为ShowForm1的方法; 我在双击TrayIcon时调用方法ShowForm1。

        private Form1 m_form1;
        private void ShowForm1()
        {
            if (m_form1 == null)
            {
                Trace.WriteLine("*CREATE*" + Thread.CurrentThread.ManagedThreadId.ToString());
                m_form1 = new Form1();
                m_form1.FormClosed += new FormClosedEventHandler(m_form1_FormClosed);
                m_form1.Show();
            }
            m_form1.BringToFront();
            m_form1.Activate();
        }

因此,当Form1需要一段时间来构造时,则可以创建2,因为当第二个调用到达时m_form1仍为null。锁定似乎不起作用,因为它是同一个线程两个调用(我猜的是UI线程),即跟踪写出* CREATE * 1两次(下面)。

[3560] *CREATE*1 
[3560] *CREATE*1 

更改代码以包含锁定语句对我没有帮助。

    private Form1 m_form1;
    private object m_Locker = new object();
    private void ShowForm1()
    {
        lock (m_Locker)
        {
            if (m_form1 == null)
            {
                Trace.WriteLine("****CREATE****" + Thread.CurrentThread.ManagedThreadId.ToString());
                m_form1 = new Form1();
                m_form1.FormClosed += new FormClosedEventHandler(m_form1_FormClosed);
                m_form1.Show();
            }
        }
        m_form1.BringToFront();
        m_form1.Activate();
    }

我该如何处理这种情况?

谢谢你们

3 个答案:

答案 0 :(得分:5)

有一个额外的布尔变量,“m_formUnderConstruction”,你在构造表单之前测试它,并在你决定构建它时立即设置它。

不幸的是,重新进入让所有这一切都变得有点蠢。我已经删除了锁,好像这是从一个不同的线程调用然后你有一个讨厌的情况,试图从一个不同的线程显示一个表单到它构建的那个。

private Form1 m_form1;
private bool m_underConstruction = false;

private void ShowForm1()
{
    if (m_underConstruction)
    {
        // We're about to show it anyway
        return;
    }
    m_underConstruction = true;
    try
    {
        if (m_form1 == null)
        {
            m_form1 = new Form1();
            m_form1.FormClosed += new FormClosedEventHandler(m_form1_FormClosed);
            m_form1.Show();
        }
    }
    finally
    {
        m_underConstruction = false;
    }
    m_form1.BringToFront();
    m_form1.Activate();
}

答案 1 :(得分:0)

使用Interlocked.Increment更改尝试的nr。如果是1,则打开表单,否则不要。并在测试后或在表格结束时使用Interlocked.Decrement。

private int openedForms = 0;
private Form1 m_form1;
private void ShowForm1()
{

    if (Interlocked.Increment(ref openedForms) = 1)
    {
       m_form1 = new Form1();
       m_form1.FormClosed += new FormClosedEventHandler(m_form1_FormClosed);
       m_form1.Show();
    }
    else
    {
       Interlocked.Decrement(ref openedForms);
    }
    if (m_form1 != null)
    {
       m_form1.BringToFront();
       m_form1.Activate();
    }
}

private void m_form1_FormClosed(object Sender, EventArgs args)
{
   Interlocked.Decrement(ref openedForms);
}

答案 2 :(得分:0)

请看这个,它处理NotifyIcon和Form1的所有鼠标事件组合。

更多信息:http://code.msdn.microsoft.com/TheNotifyIconExample