Single instance form, but not singleton

I don't understand how this is possible. Please, help!

I have a tray application. I want the form to display when the user double-clicks on the tray. I have a problem where I can get two or more forms showing a quick triple or quad click on the tray. The reason I don't want a singleton is because I want the form to be released every time it is closed to save memory, maybe this is not a good idea?

I have a field m_form1. I have a ShowForm1 method; I am calling ShowForm1 method on TrayIcon double click.

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

      

So when Form1 takes a while to build, then 2 can be created, because m_form1 is still null when the second call comes in. Blocking does not work as it is the same flow of both calls (I am guessing the UI flow), i.e. The trace writes out * CREATE * 1 twice (below).

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

      

Changing the code to enable the lock statement doesn't help me.

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

      

How should I handle this situation?

Thanks guys,

Tim.

+1


source to share


3 answers


You have an additional boolean variable "m_formUnderConstruction" that you test before creating the form and which you set up as soon as you decide to build it.

Re-tampering makes the whole thing a little unpleasant, unfortunately. I removed the lock as if it is ever being called from another thread, then you have a nasty situation where you are trying to show a form from another thread to the one it was built on.



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

      

+5


source


Use Interlocked.Increment to change nr attempts. If it is 1, open the form; otherwise, no. And use Interlocked.Decrement after test or form closing.



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

      

0


source


See this, it handles all combinations of mouse events for NotifyIcon as well as Form1.

More details here: http://code.msdn.microsoft.com/TheNotifyIconExample

0


source







All Articles