views:

154

answers:

6

I want my C# .NET application to have a form but not be a form.

When I normally startup a windows forms application, it's like the form is the master of everything else that follows:

    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
    }

Instead, I'd like to startup my program, which is then able to show a form, but is not a form itself. In other words, I don't want the master controller of the applicatin being the form, I'd like it instead to be a non-visual logical container, which has the capability to show forms, but isn't a form itself.

I'm not sure if I'm posing the question in a clear way, but I'd like to hear thoughts.

+6  A: 

You can just use Application.Run() to get a message-loop running. But you'll need to do something to listen for input - perhaps a systray etc.

Marc Gravell
This may be obvious, but I just wanted to point out that if there is no main form, then the application will have to have some logic to decide when to call Application.Exit()
Dr. Wily's Apprentice
+1  A: 

Create the app as a console app and then call Application.Run as Marc said when you need a form.

Jeff Tindall
Except that a console app will force the creation of a console window. That's probably not what Adam wants.
Steven Sudit
+2  A: 

As Mark_Gravell alluded to, Application.Run() blocks until the Form1 closes. You can open your forms on a separate thread, but that thread will be basically consumed by the form. And when you want the exe to exit, you'll have to manually kill each thread. See the following code. (It doesn't create a console window. I got this by creating a default WinForms app and changing the Program class)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Threading;

namespace WindowsFormsApplication1
{
    static class Program
    {

        static List<Thread> threads = new List<Thread>();
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            for (int i = 0; i < 10; i++)
            {
                StartThread();
                System.Threading.Thread.Sleep(500);
            }
            //kill each thread so the app will exit, otherwise, the app won't close
            //until all forms are manually closed...
            threads.ForEach(t => t.Abort());
        }

        static void StartThread()
        {
            Thread t = new Thread(ShowForm);
            threads.Add(t);
            t.Start();
        }

        static void ShowForm()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    }
}
Tim Coker
+4  A: 

You could use an ApplicationContext instead. That gets you the necessary message loop that will keep a form alive, once you decide to create one. Make your Program class look similar to this:

static class Program {
    [STAThread]
    static void Main() {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        AppContext = new ApplicationContext();
        Application.Run(AppContext);
    }
    public static void Quit() {
        AppContext.ExitThread();
    }
    public static ApplicationContext AppContext;
}

Beware that the app will not close automatically when you close the last window. Calling ExitThread explicitly is required.

Hans Passant
+1  A: 

It's fairly common to create a separate Bootstrapper component which you could move the display of the main form to:

using System;
using System.Windows.Forms;

namespace Example
{
    internal static class Program
    {
        [STAThread]
        private static void Main()
        {
            new Bootstrapper().Run();
        }
    }

    public class Bootstrapper
    {
        public void Run()
        {
            // [Application initialization here]
            ShowView();
        }

        private static void ShowView()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    }
}
Derek Greer
Exactly what I was looking for.
Adam Kane
A: 

You can also create your own ApplicationContext

static void Main()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Application.Run(AppController.Instance);
}

And within AppController.cs

namespace MyApplication
{
    public class AppController
    {
         static AppController _AppController;

         public LoginWIndow LoginWIndow;

         //Constructor
         public void AppController()
         {
             //Do what you will here, Start login form, bind events, w.e :)

             if(true) //Your check
             {
                 ShowLoginWindow();
             }
         }

         public void ShowLoginWindow()
         {
             LoginWIndow = new LoginWIndow();
             LoginWIndow.ClosedForm += new FormClosedEventHander(ExitApplication);
             LoginWIndow.Show();
         }

         public void ExitApplication(Object Sender, FormClosedEventArgs Args) 
         {
            //Some shutdown login Logic, then
            Application.Exit();
         }

         static AppController Instance
         {
            get
            {
                 if(_AppController == null)
                 {
                     _AppController = new AppController();
                 }
                 return _AppController;
            }
         }
    }
}
RobertPitt