Close one form and display another - c#

My app starts with a LoginForm where the user will enter their credentials. I need to close the LoginForm and display the DashboardForm. I'm able to do this:
public static bool OpenDashboardFormOnClose { get; set; }
public static bool OpenLoginFormOnClose { get; set; }
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
OpenDashboardFormOnClose = false;
OpenLoginFormOnClose = false;
Application.Run(new LoginForm());
if (OpenDashboardFormOnClose)
{
Application.Run(new DashboardForm());
}
if (OpenLoginFormOnClose)
{
Application.Run(new LoginForm());
}
}
The LoginForm login method:
Program.OpenDashboardFormOnClose = true;
this.Close();
The DashboardForm logout method:
Program.OpenLoginFormOnClose = true;
this.Close();
This works great when the user just logs in and then logs out.
The issue is that when a user has just logged out, and they try to log in again, the app closes instead of displaying the DashboardForm.
How do I achieve this? The user should be able to login and out as many times as they want...
Any help is appreciated.

I don't really recommend to use this approach of using many Application.Run one after another to show consecutive forms. That method starts the main message loop of the program, and generally is run once at program start and returns only once, at program exit.
Instead, make the forms open each other as needed, and leave the main message loop alone. Let's modify it to return to its almost default state:
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//Open the initial formm I'm assuming it's the login
LoginForm loginForm = new LoginForm();
loginForm.Show();
//Start the main message loop for the whole lifetime of the program
Application.Run();
}
Now, on the login form, when it's time to dismiss it and launch the main form, it does it itself instead of delegating:
//Close itself
this.Close();
//Launch the next form
DashboardForm dashboardForm = new DashboardForm();
dashboardForm.Show();
Similarly, on the dashboard when logging out you'll need to relaunch the login:
//Close itself
this.Close();
//Show the login again
LoginForm loginForm = new LoginForm();
loginForm.Show();
While all this work, this generates a problem not present before. As the main Application.Run isn't tied to a form, it won't stop running once the initial login exists, but only when explictly instructed to do so, with the net result of the process hanging after the window being closed.
To fix it, when it's time to close the application for good (not launch another form), call Application.Exit();, maybe in the Form.Closing event.

Just use a while loop to display the login and dashboard forms repeatedly. You won't need the "OpenLoginFormOnClose" flag anymore, but will need one to track whether the application should exit instead:
static class Program
{
public static bool OpenDashboardFormOnClose;
public static bool ExitApplication = false;
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
while(!ExitApplication)
{
OpenDashboardFormOnClose = false;
Application.Run(new LoginForm());
if (OpenDashboardFormOnClose)
{
Application.Run(new DashboardForm());
}
}
}
}
Then add an "exit" button to your form(s) that does:
private void btnExit_Click(object sender, EventArgs e)
{
Program.ExitApplication = true;
this.Close();
}
So now the while loop will drop out and your program will end.

this.Close or Close just closes the current form, but if it's the main form it
closes all of them.
Application.Exit() Closes all the windows from the same program.
There is no possible way to just close the main form. if you do it all the windows
opened from it will close. You can only hide the form.
To hide the form, check the code below ▼
private void Example_Click(object sender, EventArgs, e)
{
this.Hide();
this.ShowInTaskbar = false;
}
if you're on the dashboard form, and want to close all remaining windows with/or from it use ▼
Application.Exit();
Another even simpler way many people don't use to open a form ▼
new DashBoardForm().Show();

Related

C# DialogForm opening when calling for mainForm

I have a problem with my dialogForm. This is the code that opens my dialogForm (this is a login form) when my mainForm starts to run.
private void indexForm_Load(object sender, EventArgs e)
{
startForm loginForm = new startForm();
loginForm.ShowDialog();
indexUsername.Text = klasseGebruikersnaam.gebruikersnaam;
}
So when my indexForm (Main form) starts , it first loads a dialogForm, which is my login form.
Now my problem is that whenever I try to acces the mainForm from another form using this code (for example when I click a button):
this.Hide();
indexForm inf = new indexForm();
inf.Show();
The dialogForm pops up again. So I want to show my mainForm but , when I load my mainForm my dialogForm always pops up.
Any way around this?
Thanks in advance.
The problem is that you are loading your loginForm from your Main Form's Load event. Which is always going to fire after the constructor of the Main Form is called. Typically you will want to launch the loginForm from somewhere before the Main Form is loaded. You could do this in your Program.cs file and make it the main entry point of the program. Or just simply check if the user is already logged in.
Here is an example of both:
Program.cs
static void Main()
{
//Auto-generated code that VS writes for you
using (var loginForm = new LoginForm())
{
if (loginForm.ShowDialog() == DialogResult.Yes) //Presumably it would only return Yes if the login was successful.
{
Application.Run(new MainForm()); //Or however you call your main form
}
}
}
Of you can just put a property on the Main Form that determines if the user is logged in. Then you can call it in the Load event still.
Load Event
if(!this.UserLoggedIn)
{
loginForm.ShowDialog();
//Do something with the dialog result.
}
In my opinion it is better to user the Program.cs approach because if the user fails to login correctly, you can just exit or handle it as needed without loading your Main Form at all. The way you currently have it, the main form must load before the login form is shown, which could be problematic.
Well, you should remove that code from your main form and call it before showing the main form.
Or you could simply set a global variable that keeps the info for the current logged in user and, if that variable is not null, don't call again the login form
So, supppose that you login form prepare an instance variable of type LoggedinUser
public class LoggedinUser
{
public string NickName {get;set;}
public string UserRole {get; set;}
...
}
then in an utility class (or in your index form) you could have a static variable
public static LoggedinUser currentOperator = null;
in your in index_form you could write
if(GlobaClass.currentOperator == null)
{
using(startForm loginForm = new startForm())
{
if(loginForm.ShowDialog() == DialogResult.OK)
GlobalClass.currentOperator = loginForm.LoggedUser;
}
}
looks like you need to add a check to see if the user is logged in around the
loginForm.ShowDialog();
something like
if(!UserLoggedIn())
{
loginForm.ShowDialog();
}

Splash screen to show up in the middle of application

I have a list of report names displayed as Tree hierarchy in ReportViewer control. When user clicks on a report name, an input form loads, user enters some values and presses OK. At this point, Splash screen should load while the backend process is happening (connecting to DB, retrieving values etc). Once the report is loaded in Reportviewer editor, the splashscreen should close.
So far, I am able to display the splash screen however it gets stuck at that point, the actual report does not load and the splash screen stays on forever.
Is it possible to use splashscreen in the middle of application, not at app launch? If so, how do I continue with loading report?
static class Program
{
[STAThread]
static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new SnapPlusReports());
//new SplashScreenApp().Run(args);
}
}
public class SplashScreenApp : WindowsFormsApplicationBase
{
private static SplashScreenApp _application;
public static void Run(Form form)
{
_application = new SplashScreenApp { MainForm = form };
_application.Run(Environment.GetCommandLineArgs());
}
protected override void OnCreateSplashScreen()
{
this.SplashScreen = new ShowProgress();
base.OnCreateSplashScreen();
}
}
I have done this before by making a new form at run time dynamically with code. Make sure you set all the options up, especially FormBorderStyle to none, or something like that so the user can't close it. Then simply manipulate labels that appear on that form, and eventually close it once your process is complete.
This way you don't have to worry about threading and a nice side effect is that the initial form won't be clickable.
For example I have an about form that pops up during run time (granted I don't change anything on it but the idea is there:
AboutForm aboutForm = new AboutForm();
aboutForm.StartPosition = FormStartPosition.CenterParent;
Label lblAbout = new Label();
Version applicationVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
lblAbout.Text = applicationVersion.ToString();
lblAbout.Location = new Point(145,104);
aboutForm.Controls.Add(lblAbout);
aboutForm.ShowDialog();
This shows the current programs version number, etc. There are other labels that already exist on the form (I created it visually first and then called an instance of it).
Hope this helps!
...Catch other instances and gracefully exit if you need only one copy of your app in memory at a given time
static void Main()
{
Application.EnableVisualStyles();
bool exclusive;
System.Threading.Mutex appMutex = new System.Threading.Mutex(true, "MY_APP", out exclusive);
if (!exclusive)
{
MessageBox.Show("Another instance of xxxx xxxBuilder is already running.","MY_APP",
MessageBoxButtons.OK,
MessageBoxIcon.Exclamation );
return;
}
Application.SetCompatibleTextRenderingDefault(false);
xxxWindowsApplication.InitializeApplication();
Application.Run(new frmMenuBuilderMain());
GC.KeepAlive(appMutex);
}
In the main form load you could do something like:
private void frmMenuBuilderMain_Load(object sender, EventArgs e)
{
//Show Splash with timeout Here--
if(!SystemLogin.PerformLogin())
{
this.Close();
return;
}
tmrLoad.Enabled = true;
}

How to handle several windows form

I'm doing a small project to store movies. I'm using three windows form, a intro form, a main form and a new movie form. I also have a class that I call MovieManager that is the heart of the application. My problem is that I'm not sure how I should handle this windows.
Let's say I want the application to start with the intro form and when the user click on the OK-button the main form should appear. What is the best way to do this? Should I in the Program.cs create an object of the MovieManager class that show and hide the different windows form or should I in the Program.cs just start by showing the intro form?
You can simply do all staff in Program.cs when starting application. Show your IntroForm as dialog. If user clicks OK, then start main application form, otherwise close application.
static void Main()
{
IntroForm introForm = new IntroForm();
if (introForm.ShowDialog() != DialogResult.OK)
{
Application.Exit();
return;
}
Application.Run(new MainForm());
}
If you need single MovieManager instance for all these forms, then you can create it in Main method and pass same instance to IntroForm and MainForm:
MovieManager movieManager = new MovieManager();
IntroForm introForm = new IntroForm(movieManager);
if (introForm.ShowDialog() != DialogResult.OK)
{
Application.Exit();
return;
}
Application.Run(new MainForm(movieManager));
Also you can implement MovieManager as Singleton, which will be accessible everywhere via static property MovieManager.Instance.
What you call intro form, I should call a splash screen. In the program.cs I should just pop-up the splash screen (with a logo, title and info about the application, version number, etc.). The splash screen is shown for a certain amount of time (use a timer for this, or Thread.Sleep is alos possible altough a bit heavy).
When the splash screen closes show the MainForm is shown a from there you can instantiate a MovieManager or use a static MovieManager (it depends on its use). From the mainform you can then just instantiate and show new movie form(s).
We use a piece of code something like this:
static void Main(string[] args)
{
try
{
SplashScreen.ShowSplashScreen();
Application.DoEvents();
SplashScreen.WaitForVisibility(.5);
bool starting = true;
while (starting)
{
try
{
SplashScreen.SetStatus("Initialize mainform...");
starting = false;
Application.Run(new MainForm());
}
catch (Exception ex)
{
if (starting)
starting = XtraMessageBox.Show(ex.Message, "Fout bij initialiseren", MessageBoxButtons.RetryCancel, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1) == DialogResult.Retry;
else
throw (ex);
}
}
}
catch (Exception ex)
{
if (ex is object)
XtraMessageBox.Show(ex.Message, "Algemene fout", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
}
}
And code in the splashscreen (excerpt) looks like this:
if (_splashForm == null)
{
ThreadPool.QueueUserWorkItem(RunSplashForm, null);
while (_splashForm == null || _splashForm.IsHandleCreated == false)
{
System.Threading.Thread.Sleep(50);
}
}
Maybe these links will also provide you some usefull information:
http://www.reflectionit.nl/Articles/Splash.aspx
And we used this as the basis for our own code:
http://www.codeproject.com/Articles/5454/A-Pretty-Good-Splash-Screen-in-C
There are different ways to show a new form. you can use MdiWinForm first you must change IsMdiContainer property to true then use these codes in the MainForm :
Form2 f2;
private void button1_Click(object sender, EventArgs e)
{
if (f2 == null) {
f2 = new Form2();
f2.MdiParent = this;
f2.FormClosed += delegate { f2 = null; };
f2.Show();
}
else {
f2.Activate();
}
}

c# MDI parent form + login form error

I get this error:
Starting a second message loop on a single thread is not a valid operation. Use Form.ShowDialog instead.
When trying to exit my app after disposing a login form. To clarify, this is what I'm doing in my form:
public frmMainMDI()
{
InitializeComponent();
frmLogin frmLogin_ = new frmLogin(); //create new login form
frmLogin_.ShowDialog(); //show i
if (frmLogin_.DialogResult == DialogResult.Cancel) //if user pressed cancel
{
frmLogin_.Dispose(); //dispose login form
Application.Exit(); //Exit application. If I used this line, it throws the error stated above in Program.cs
//this.Dispose(); //If I try to use this one instead, it throws an 'already disposed' error
//this.Close(); //same error as .dispose
}
else
{
intCurrentLoggedInStaffID = frmLogin_.intStaffID;
}
}
And this is in my program.cs:
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new frmMainMDI()); //this is the line that bugs out
}
I don't quite get it. It almost looks like the app is trying to restart itself when I try to .Exit it. Am I missing something pretty fundamental here? (I'm guessing the answer is 'yes')
I can't quite explain why you are getting this error, but I can suggest a better way to do it. If I understand your intentions correctly, you want to show a login form before the main MDI window is shown and exit your application, if the user pressed cancel in the login form.
Your program.cs:
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
LoginForm loginForm = new LoginForm();
if (loginForm.ShowDialog() != DialogResult.Cancel)
{
MainMdiForm mainMdiForm = new MainMdiForm();
mainMdiForm.intCurrentLoggedInStaffID = loginForm.intStaffID;
loginForm.Dispose();
loginForm = null;
Application.Run(mainMdiForm);
}
}
Your constructor in the MainMdiForm should only contain the call to InitializeComponents.
You're attempting to exit the application (which means shut down the main message loop) in the middle of a constructor (which is bad in general) which is being run in the method which is supposed to be starting up that message loop in the first place. So you have contradictory operations going here.
What I would suggest is that you move your login form/dialog code into your program.cs/Main() function. So something like this:
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
using(frmLogin frmLogin_ = new frmLogin()) { //create new login form
frmLogin_.ShowDialog(); //show i
if (frmLogin_.DialogResult == DialogResult.Cancel) //if user pressed cancel
{
return; // This exits your application
}
}
Application.Run(new frmMainMDI()); //this is the line that bugs out
}

Any way to create a hidden main window in C#?

I just want a c# application with a hidden main window that will process and respond to window messages.
I can create a form without showing it, and can then call Application.Run() without passing in a form, but how can I hook the created form into the message loop?
Is there another way to go about this?
Thanks in advance for any tips!
Excellent! That link pointed me in the right direction. This seems to work:
Form f = new Form1();
f.FormBorderStyle = FormBorderStyle.FixedToolWindow;
f.ShowInTaskbar = false;
f.StartPosition = FormStartPosition.Manual;
f.Location = new System.Drawing.Point(-2000, -2000);
f.Size = new System.Drawing.Size(1, 1);
Application.Run(f);
To keep it from showing up in Alt-Tab, you need it to be a tool window. Unfortunately, this prevents it from starting minimized. But setting the start position to Manual and positioning it offscreen does the trick!
In the process of re-writing a VC++ TaskTray App, in C# .NET, I found the following method truly workable to achieve the following.
No initial form dislayed at startup
Running Message Loop that can be used with Invoke/BeginInvoke as needed as IsWindowHandle is true
The steps I followed:
Used an ApplicationContext in Application.Run() Instead of a form. See http://www.codeproject.com/Articles/18683/Creating-a-Tasktray-Application for the example I used.
Set the Form's ShowInTaskbar property to true within the GUI Designer. (This seems counter productive but it works)
Override the OnLoad() method in your Form Class setting Visible and ShowInTaskbar to false as shown below.
protected override void OnLoad(EventArgs e)
{
Visible = false;
ShowInTaskbar = false;
base.OnLoad(e);
}
I know this is old question, but it ranks well in google, so I will provide my solution anyway.
I do two things:
private void Form_Load(object sender, EventArgs e)
{
Opacity = 0;
}
private void Form_Shown(object sender, EventArgs e)
{
Visible = false;
Opacity = 100;
}
The best way is to use the following 1-2 lines in the constuctor:
this.WindowState = FormWindowState.Minimized;
this.ShowInTaskbar = false; // This is optional
You can even set the Minimized property in the VS Property window.
You can create a class that inherits from System.Windows.Forms.NativeWindow (which provides basic message loop capability) and reference the Handle property in its constructor to create its handle and hook it into the message loop. Once you call Application.Run, you will be able to process messages from it.
I solved the problem like this:
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Main main = new Main();
Application.Run();
//Application.Run(new Main());
}
This code resides in the Program.cs file, and you can see the original Application.Run method call commented out. I just create a Main class object (my main form class is named Main) and start application message loop w/o any parameters. This starts the application, initializes any form components but doesn't show the form.
Note: you have to have some method to get your window showing (like system tray icon, hotkey or timer or anything you might like).
public partial class Form1 : Form
{
private bool _isApplicationRun;
public Form1(bool applicationRun)
{
InitializeComponent();
_isApplicationRun = applicationRun;
}
protected override void SetVisibleCore(bool value)
{
if (_isApplicationRun)
{
_isApplicationRun = false;
base.SetVisibleCore(false);
return;
}
base.SetVisibleCore(value);
}
}
static class Program
{
[STAThread]
static void Main()
{
Application.Run(new Form1(true));
}
}
Why can't you just pass the form when you call Application.Run? Given that it's clearly a blocking call, on what event do you want to show the form? Just calling form.Show() should be enough.
Using Kami's answer as an inspiration, I created a more complete concept. If you use this solution, don't ever show the hidden window. If you do, the user might close it and then you've lost the ability to control the application exit in an orderly way. This approach can be used to manage a Timer, NotifyIcon, or any other component that is happy living on an invisible form.
using System;
using System.Windows.Forms;
namespace SimpleHiddenWinform
{
internal class HiddenForm : Form
{
private Timer _timer;
private ApplicationContext _ctx;
public HiddenForm(ApplicationContext ctx)
{
_ctx = ctx;
_timer = new Timer()
{
Interval = 5000, //5 second delay
Enabled = true
};
_timer.Tick += new EventHandler(_timer_Tick);
}
void _timer_Tick(object sender, EventArgs e)
{
//tell the main message loop to quit
_ctx.ExitThread();
}
}
static class Program
{
[STAThread]
static void Main()
{
var ctx = new ApplicationContext();
var frmHidden = new HiddenForm(ctx);
//pass the application context, not the form
Application.Run(ctx);
}
}
}
Form1 f1=new Form1();
f1.WindowState = FormWindowState.Minimized;
f1.ShowInTaskbar = false;
in the Form1 code file add this.Visible = false; to the constructor.
This will hide the window but it will flash for a sec before it is hidden. Alternatively you can write your own Application.Run command.
for more info http://social.msdn.microsoft.com/forums/en-US/winforms/thread/dece45c8-9076-497e-9414-8cd9b34f572f/
also you may want to set the this.ShowInTaskbar to false.
You should look at creating a 'service' as this is an application without a form.
See http://support.microsoft.com/kb/816169

Categories

Resources