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;
}
Related
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();
This question already has answers here:
Communicate between two windows forms in C#
(12 answers)
Closed 7 years ago.
I am making a game, and I have 3 main forms that I am using, one is the start menu, one is the main game form, and the other is a create map form. My question is directed to how can I send variables between them. I know of the classic form setup, where you show one form from the other, and pass information like this...
Form1 form = new Form1();
form.Show();
form.varible = ...
But i don't like how the previous form is still showing, and form.ShowDialog isn't what I am going for either. I have a system where you cycle through forms, where it opens your new form and closes the old one, and it works great, except I don't know how to send information to the new form. I changed the Program.cs code to look like this
public static bool OpenForm1OnClose { get; set; }
public static bool OpenForm2OnClose { get; set; }
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
OpenForm1OnClose = true;
OpenForm2OnClose = false;
while (OpenForm1OnClose || OpenForm2OnClose)
{
if(OpenForm1OnClose)
Application.Run(new Form1());
if (OpenForm2OnClose)
Application.Run(new Form2());
}
}
This is just a testing program right now that switches between two forms - click one button and it goes to the other form and closes the one you were on. Here's what the button click code looks like
private void button1_Click(object sender, EventArgs e) // form1's button
{
Program.OpenForm2OnClose = true;
this.Close();
}
That is all the code right there, nothing more to it really. Any Idea's on how to pass variables would be awesome, or if its straight up impossible, advice on a good way to switch between forms would be helpful. Thanks for reading
If you're asking what I think, the answer is simple. You just need to have your constructor take the information as its args.
private var myInfo;
public Form1(var myInfo_)
{
InitializeComponent();
myInfo = myInfo_;
}
I hope this is in fact what you want.
This question already has answers here:
How to start WinForm app minimized to tray?
(6 answers)
Closed 8 years ago.
I have developed a windows form application and installer for it. I had installed that app on my machine. Now when I restart my PC or Log in on machine the App gets launched and shown on desktop. A sys tray icon is also shown in sys-tray. Now I want to keep app hidden and only sys tray icon should be visible. Means app should not be displayed on screen but sys tray icon should be visible. I have used "CreateProcessAsCurrentUser" method in which I have set the value of "STARTF_USESHOWWINDOW" to different values. But still its not working. Also I am not getting which method of Application gets called on System startup. Is it Main() function from Program.cs file. Please tell me the solution and also the Function which gets called.
[STAThread]
Main() function code: `static void Main()
{
Mutex mutex = new Mutex(false, "Application Name");
try
{
if (mutex.WaitOne(0, false))
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
Application.Run(new MainForm());
}
else
{
IntPtr pf = NativeMethods.FindWindow(null, "Application Name");
NativeMethods.ShowWindow(pf, 0);
NativeMethods.SetForegroundWindow(pf);
}
}
I have set the value of flag as below.
[Flags]
public enum CreateProcessFlags : uint
{
STARTF_USESHOWWINDOW = 0x00000000,
}
try this.... put this in your form:
protected override void SetVisibleCore(bool value)
{
base.SetVisibleCore(false);
}
this will always now make the form invisible.
you will need some logic though to determine if it should be shown or not from other parts of your app. for example, set a global bool value and modify the code above to use that.
alternatively, you can use this:
protected override void OnVisibleChanged(EventArgs e)
{
base.OnVisibleChanged(e);
this.Visible = false;
}
but you will see a bit of a flash when you run the app straight away. you then, again, need to control when to make it visible so check the global bool value for the visible property so you can eventually display the form
have you try this?
private void Form1_Load(object sender, EventArgs e)
{
this.WindowState = FormWindowState.Minimized;
this.Hide();
this.ShowInTaskbar = true;
}
then use notifyicon
My WinForms app's main window is slow to load (up to 20 seconds, depending on arguments), so it needs a splash screen.
The main window constructor is slow because it exercises thousands of lines of code (some of it beyond my influence). Sometimes this code pops up message boxes.
I've tried two splash screen designs, they each have problems. Any better ideas?
Splash screen with BackgroundWorker
static void Main(string[] args)
{
var splash = !args.Contains("--no-splash");
if (splash)
{
var bw = new BackgroundWorker();
bw.DoWork += (sender, eventArgs) => ShowSplash();
bw.RunWorkerAsync();
}
var app = new FormMain(args); // slow. sometimes opens blocking message boxes.
Application.Run(app);
}
private static void ShowSplash()
{
using (var splash = new FormSplash())
{
splash.Show();
splash.Refresh();
Thread.Sleep(TimeSpan.FromSeconds(2));
}
}
Problems:
Splash screen sometimes expires before main window open (user thinks app has crashed)
Main window sometimes minimises when splash closes.
Splash screen with WindowsFormsApplicationBase
sealed class App : WindowsFormsApplicationBase
{
protected override void OnCreateSplashScreen()
{
this.SplashScreen = new FormSplash();
}
protected override void OnCreateMainForm()
{
// slow. sometimes opens blocking message boxes.
this.MainForm = new FormMain(this.CommandLineArgs);
}
}
Problems:
Any MessageBoxes opened appear behind splash screen, silently. User won't notice it and thinks app is stuck.
If splash screen is 'always on top', the message box is inaccessible and unclickable.
I agree with Hans Passant in that the code needs to be re-evaluated as the design seems incorrect.
As for the problem at hand, you should be able to resolve this by creating your own instance of a messageBox.
I tested using this code;
public DialogResult TopMostMessageBox(string message, string title, MessageBoxButtons button, MessageBoxIcon icon)
{
return DisplayMessageBox(message, title, button, icon);
}
public DialogResult DisplayMessageBox(string message, string title, MessageBoxButtons buttons, MessageBoxIcon icon)
{
DialogResult result;
using (var topmostForm = new Form {Size = new System.Drawing.Size(1, 1), StartPosition = FormStartPosition.Manual})
{
var rect = SystemInformation.VirtualScreen;
topmostForm.Location = new System.Drawing.Point(rect.Bottom + 10, rect.Right + 10);
topmostForm.Show();
topmostForm.Focus();
topmostForm.BringToFront();
topmostForm.TopMost = true;
result = MessageBox.Show(topmostForm, message, title, buttons, icon);
topmostForm.Dispose();
}
//You might not need all these properties...
return result;
}
//Usage
TopMostMessageBox("Message","Title" MessageBoxButtons.YesNo, MessageBoxIcon.Question)
Again, I need to stress that I agree that the original code needs to be re-factored and am only providing a possible solution to the question.
Hope this helps?
You can implement our own message box and use TopMost property, with TopMost you will get message in-front of splash screen loader.
More about topmost: http://msdn.microsoft.com/en-us/library/system.windows.forms.form.topmost.aspx
In the end, moved the slow code from the constructor to a handler for the OnShown event.
Used WindowsFormsApplicationBase for splash screen as Hans Passant suggested, carefully checked the remaining constructor code to make sure it'll never open an message boxes.
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