Home > front end >  I have more than one Form in the Solution, how to change the starting Form?
I have more than one Form in the Solution, how to change the starting Form?

Time:01-29

I have more than 1 forms in solution, how to make required form as default to run?

Apart from the option available in project by default Program.cs to change:

Application.Run(new Form1());

Is there any other method so that I do not have to open each and every time the Program.cs file to change the startup form.?

CodePudding user response:

If you want to be able to change the startup form, without having to modify Program.cs and rebuilding your application, you can do the following:

Put the information which form to launch in a configuration file (in any format e.g. json, ini file, plain txt file).
You'll also need a method to load and parse this config file. Let's say you have a class Config with the parsed configuration, and a field like WhichForm identifying the form you want to launch.

Then change the current Program.cs from:

Application.Run(new Form1());

To something like:

Config cfg = LoadConfig();

// Decide which form to use:
Form theForm = null;
switch (cfg.WhichForm) // assuming Config.WhichForm is a FormType enum
{
    case FormType.F1 : theForm = new Form1(); break;
    case FormType.F2 : theForm = new Form2(); break;
    default : // handle error
}

// Launch the selected form:
Debug.Assert(theForm != null);
Application.Run(theForm);

Now you don't have to build your project to change the startup form - just change the config file and restart the application.

CodePudding user response:

Reading your question carefully I ask myself why would you want to do this? And sure! I can think of at least one scenario where the MainForm and the form you want to show first are different. So, for purposes of demonstration, consider an "app that requires a login" as an example.

App with Login

screenshot

In Program.cs you'll still want to call Application.Run(new MainForm()) even though in this case, it's the LoginForm that should present first. But here's a simple trick that ensures window handles will be created in the correct sequence (this can be adapted for your actual use case).


Prevent MainForm from becoming Visible

Override SetVisibleCore so that the MainForm can't be visible unless some condition is met, e.g. IsLoggedIn.

public partial class MainForm : Form
{
    .
    .
    .
    protected override void SetVisibleCore(bool value) =>
        base.SetVisibleCore(value && IsLoggedIn);
}

Ensure MainForm.Handle is created "anyway"

In the CTor force the creation of the main form Handle. This ordinarily happens later in the course of making the main form visible, but we're not going to allow that. The main form Handle is needed now and needs to be first in line.

public MainForm()
{
    InitializeComponent();
    // A handle is needed before calling BeginInvoke, so get one.
    _ = Handle;
    // Call BeginInvoke on the new handle so as not to block the CTor.
    BeginInvoke(new Action(()=> execLoginFlow()));
    // Ensure final disposal of login form when app closes. Failure
    // to properly dispose of window may cause an exit hang.
    Disposed  = (sender, e) => _loginForm.Dispose();
    // Provide a means of logging out once the main form shows.
    buttonSignOut.Click  = (sender, e) => IsLoggedIn = false;
}

This way, we can have it both ways and exec a login flow first but without the login form trying to become the main window.

private void execLoginFlow()
{
    Visible = false;
    while (!IsLoggedIn)
    {
        _loginForm.StartPosition = FormStartPosition.CenterScreen;
        if (DialogResult.Cancel == _loginForm.ShowDialog(this))
        {
            switch (MessageBox.Show(
                this,
                "Invalid Credentials",
                "Error",
                buttons: MessageBoxButtons.RetryCancel))
            {
                case DialogResult.Cancel: Application.Exit(); return;
                case DialogResult.Retry: break;
            }
        }
        else
        {
            IsLoggedIn = true;
        }
    }
}

Bind MainForm Visible to IsLoggedIn

Since logins can come and go, just bind the visibility of MainForm to changes of the login state.

protected override void SetVisibleCore(bool value) =>
    base.SetVisibleCore(value && IsLoggedIn);

bool _isLoggedIn = false;
public bool IsLoggedIn
{
    get => _isLoggedIn;
    set
    {
        if (!Equals(_isLoggedIn, value))
        {
            _isLoggedIn = value;
            onIsLoggedInChanged();
        }
    }
}

private void onIsLoggedInChanged()
{
    if (IsLoggedIn)
    {
        WindowState = FormWindowState.Maximized;
        Text = $"Welcome {_loginForm.UserName}";
        Visible = true;
    }
    else execLoginFlow();
}
  • Related