I have a method which is invoked in class A and it is defined in class B:
class B{
[STAThread]
public static void ScanForAxisCameras() {
DNSSDService service = new DNSSDService();
DNSSDEventManager eventManager = new DNSSDEventManager();
eventManager.ServiceFound += new _IDNSSDEvents_ServiceFoundEventHandler(eventManager_ServiceFound);
DNSSDService browse = service.Browse(0, 0, "_axis-video._tcp", null, eventManager);
Application.Run();//if not invoked everything above does not start
}
}
class A{ ...before invoking..... B.ScanForAxisCameras(); ....after invoking....}
The code in class B "starts"/works only if I invoke Application.Run(). But it causes that all the code in class A ....after invoking.... method does not work. How to handle it so it will not freeze the application?
Edit: the class A is class MainWindow.xaml.cs. It is WPF application.
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e) {
createGUI();
}
private void createGUI() {
LocalNetworkScanner.ScanForAxisCameras();//when there is no Application.Run() ScanForAxisCameras() does not work.
}
}
The WPF UI thread on which you call ScanForAxisCameras() already has a message loop. I believe the problem with your code is that all objects you create inside ScanForAxisCameras have the local scope:
public static void ScanForAxisCameras() {
DNSSDService service = new DNSSDService();
DNSSDEventManager eventManager = new DNSSDEventManager();
eventManager.ServiceFound += new _IDNSSDEvents_ServiceFoundEventHandler(eventManager_ServiceFound);
DNSSDService browse = service.Browse(0, 0, "_axis-video._tcp", null, eventManager);
Application.Run();//if not invoked everything above does not start
}
Without Application.Run(), your objects (service, eventManager, browse) may be getting destroyed and finalized as soon as ScanForAxisCameras finishes. So, the events you're looking for (like ServiceFound) may not even have a chance to get fired.
If you call Application.Run(), then ScanForAxisCameras doesn't exit (at least not until Application.Run() itself exits). That keeps your objects alive and functional.
Try refactoring your code to keep the references to these objects in member fields of your class (or in static variables, FWIW). I believe that should fix the problem.
[EDITED] On a side note, the [STAThread] attribute doesn't make sense in that context (unless you use ScanForAxisCameras as an entry point for a new thread - apparently, that's not the case here).
You can introduce a new Run()-method in your App in the App.xaml.cs file.
Here you can perform custom actions before the application itself gets initialized.
Further information here.
public partial class App : Application
{
public new void Run()
{
// Do your stuff here
B.DoStuff();
// Call the base method
base.Run();
}
}
Application.Run starts the message loop for that particular thread, if there is no message loop then there is no notification for your objects to know they have to do something.
The code in class B "starts"/works only if I invoke Application.Run(). But it causes that all the code in class A ....after invoking.... method does not work.
Run is a blocking call therefore any code after that call is not reachable until the application is closing down i.e. when you exit the message loop.
How to handle it so it will not freeze the application?
In short, you can't. Run will always block so any code you need to run as part of your application startup will have to happen before the call.
After your edit to mention that this is a WPF application then Application.Run as a static method is not the right way to go here. If you need to run initialization when your application starts then you can do what has already been suggested and override the Run method of the Application class, or alternatively (maybe more appropriately) you can hook into the OnStartup event e.g.
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
// code before startup
base.OnStartup(e);
// code after startup
}
}
It seems as though in this situation you would need to add Application.Run() in a different class. Run() accepts nothing, ApplicationContext, Form. This controls the lifetime of the application and should be called before class A, unless class A is the entry point.
See http://msdn.microsoft.com/en-us/library/ms157900.aspx for details.
A Windows Forms application starts when the Main method is called. You can implement initialization procedures on the Main function. However, to initialize a Windows Forms application fully and start it routing Windows Forms events, you need to invoke Application.Run.
you can read about Application here
Related
I have an Console Application started as [STAThread].
That application should open a seperate Wpf UI for entering some settings.
The functions for that:
private static void openUI()
{
var application = new System.Windows.Application();
//referenced project in the same solution
var ui = new ManagerUI.MainWindow();
//blocks execution
application.Run(ui);
application.Shutdown();
}
Opening the UI for the first time works as expected.
The problem occurs when opening the UI for the second time.
I get an System.InvalidOperationException, saying that I cannot run more than one Application-Instance in the same AppDomain.
For saving ram, it must be closed between the operations.
I also tried to create the System.Windows.Application in the constructor.
But as soon as I run the application the second time, I get a very similiar exception.
The InitializeComponents() method of the UI throws an System.InvalidOperationException, saying that the Object is going to be terminated.
The StackTraces shows that the error appears when the xaml is parsed, so I conclude it cannot open it, because it is still opened by the first execution.
Neither calling ui.Close() nor calling application.Shutdown() solves the problem (Environment.Exit() closes everything, including my Console Application).
The ram profiler indicates, not everything was closed correctly because it shows an higher use after the Window was closed, than before it was opened in the firts place.
How do I properly close the Application instance, or how do I re-use it to run an Wpf Application multiple times?
Having looked at the source code for the Application class, it doesn't look like you will be able to work around this, as various static fields are initialized by the class constructor:
public Application()
{
...
lock(_globalLock)
{
if (_appCreatedInThisAppDomain == false)
{
...
_appInstance = this;
...
_appCreatedInThisAppDomain = true;
}
else
{
throw new InvalidOperationException(...);
}
}
}
...
static private object _globalLock;
static private bool _appCreatedInThisAppDomain;
static private Application _appInstance;
...
Basically the constructor sets _appCreatedInThisAppDomain to true, and as that field is private you have no way of setting it back*.
I think the only way of achieving something similar to what you want is to write a separate WPF application, then use the Process class to launch that from your console application. Alternatively, you could theoretically create a separate AppDomain to host your WPF stuff but that would be a lot more complicated.
[*] other than using Reflection, but let's not go there!
You may create a class that derives from MarshalByRefObject:
public class AppDomainWrapper : MarshalByRefObject
{
public void openUI()
{
var application = new System.Windows.Application();
var ui = new Window();
application.Run(ui);
application.Shutdown();
}
}
...and execute its openUI() method in its own application domain:
[STAThread]
static void Main(string[] args)
{
const int n = 2;
for (int i = 0; i < n; ++i)
{
AppDomain appDomain = AppDomain.CreateDomain("AppDomain");
AppDomainWrapper application = appDomain.CreateInstanceAndUnwrap(typeof(AppDomainWrapper).Assembly.FullName, typeof(AppDomainWrapper).FullName) as AppDomainWrapper;
application.openUI();
AppDomain.Unload(appDomain);
}
}
Have a look at this question:Does a WPF Application Actually Need Application.Run?.
Basically it says, that you can open windows using window.ShowDialog() method without Application instance
The think is that Application.Run does not do anything important but run Dispatcher loop. ShowDialog have its own Dispatcher. You can create Application singleton instance however, since it contains some shared resources.
Hack(run it after application.Shutdown()). I use this in tests:
var field = typeof(Application).GetField(
"_appCreatedInThisAppDomain",
BindingFlags.Static | BindingFlags.NonPublic) ??
throw new InvalidOperationException(
"Field is not found: _appCreatedInThisAppDomain.");
field.SetValue(null, false);
Steven Rands shows the problem.
I have the same problem in an external add-in. But I need an application object for xaml resources and a valid Application.Current.
In my eyes this is a bug. If you call Shutdown() this member should also be reset to false.
This is a tray-icon-only Windows Forms application. I'm trying to use argument to control something and change the text on the form for showing the status information.
But I found when I use argument to call it during it's running, the things I want to change are null (NotifyIcon() and MenuItem()), seems it ran a different application when I using arguments. I also tried Invoke() but there is no this definition in NotifyIcon().
Here is the code I wrote:
static void Main(string[] args)
{
if (args.Length > 0)
{
Arg_Call(args[0]);
}
if (new Mutex(true, "{XXX}").WaitOne(TimeSpan.Zero, true))
{
Init_Tray();
Application.Run();
}
}
private static NotifyIcon trayicon;
private static void Init_Tray()
{
trayicon = new NotifyIcon() { Icon = new Icon(#"D:\projects\Icon.ico"), Text = "Waiting", Visible = true };
trayicon.Visible = true;
Application.Run();
}
private static void Arg_Call(string args)
{
trayicon.Invoke((MethodInvoker)delegate {
trayicon.Text = "OK";
}); //from: https://stackoverflow.com/a/661662/8199423
}
Where am I wrong? How to and what is the best way to change the NotifyIcon.Text property in the running form via command-line-arguments?
I am sorry I was unable to adequately explain why your question is a duplicate of the existing "single-instance-application" questions. I will try to reiterate the train of thought here:
You wrote "How to and what is the best way to change the texts in the running form via command-line-arguments?"
Your requirement involves a currently-running process, which is presenting the NotifyIcon in the task tray, and the desire to use the command-line to modify that currently-running process's state.
It is a simple fact that when you type anything on the command line, it starts a whole new process. That process is necessarily different from the process that is already running, and which is presenting the NotifyIcon in the task tray.
Putting all of the above together, we have the conclusion that you want a new process that you start on the command line to interact with an existing process. And the simplest way to achieve that goal is to use the built-in single-instance-application support found in .NET. This is because the support for single-instance-applications includes automatic passing of the new command line arguments to the previous running program. Hence, the duplicate.
As I mentioned earlier, you should try to develop the skill to generalize and see how seemingly new problems are really just old problems in disguise and which you or someone else already knows how to solve.
In the same way that all problem solving can be summarized as "break the large problem down into smaller problems, repeat as necessary until all of the smaller problems are problems you already know how to solve", programming is very often not a matter of solving new problems, but rather of recognizing how your current problem is really a problem you already know how to solve.
All that said, I have the impression that you're still having difficulty figuring out how to apply that information to your specific scenario. So, perhaps this is an opportunity to illustrate the validity of the philosophy I espouse, by showing you how your seemingly different problem really is the problem I claim it is. :)
So, let's start with your original scenario. I am not using the code you posted, because it's mostly code that isn't needed. It seemed simpler to me to start from scratch. To do that, I wrote a little TrayManager class that encapsulates the actual NotifyIcon part of the functionality:
class TrayManager : IDisposable
{
private readonly NotifyIcon _notifyIcon;
public TrayManager()
{
_notifyIcon = new NotifyIcon
{
ContextMenu = new ContextMenu(new[]
{
new MenuItem("Exit", ContextMenu_Exit)
}),
Icon = Resources.TrayIcon,
Text = "Initial value",
Visible = true
};
}
public void Dispose()
{
Dispose(true);
}
public void SetToolTipText(string text)
{
_notifyIcon.Text = text;
}
protected virtual void Dispose(bool disposing)
{
_notifyIcon.Visible = false;
}
private void ContextMenu_Exit(object sender, EventArgs e)
{
Application.ExitThread();
}
~TrayManager()
{
Dispose(false);
}
}
The above hard-codes the context menu for the icon. Of course, it a real-world program, you'd probably want to decouple the menu from the above class, for greater flexibility.
The simplest way to use the above would look something like this:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
using (TrayManager trayManager = new TrayManager())
{
Application.Run();
}
}
}
So, how do we modify the above so that when you run the program again, you can change the Text property of the NotifyIcon with the command-line arguments you type? That's where the single-instance application comes in. As seen in the duplicate I marked earlier, What is the correct way to create a single-instance application?, one of the simplest ways to accomplish this is to use the Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase class, which has built right in support for single-instance applications and a mechanism for delivering new command line arguments to the existing process.
The one little draw-back is that this class was designed for Winforms programs, with the assumption that there will be a main form. To use it will require creating a Form instance. For a program without the need for an actual form, this means creating a Form instance that is never shown, and making sure that it's never shown does require a little bit of finagling. Specifically:
class TrayOnlyApplication : WindowsFormsApplicationBase
{
public TrayOnlyApplication()
{
IsSingleInstance = true;
MainForm = new Form { ShowInTaskbar = false, WindowState = FormWindowState.Minimized };
// Default behavior for single-instance is to activate main form
// of original instance when second instance is run, which will show
// the window (i.e. reset Visible to true) and restore the window
// (i.e. reset WindowState to Normal). For a tray-only program,
// we need to force the dummy window to stay invisible.
MainForm.VisibleChanged += (s, e) => MainForm.Visible = false;
MainForm.Resize += (s, e) => MainForm.WindowState = FormWindowState.Minimized;
}
}
The only thing in the above that gives us the single-instance application behavior we want is the setting of IsSingleInstance = true;. Everything else is there just to satisfy the requirement that some Form object is present as the MainForm, without actually showing that object on the screen.
Having added the above class to the project, we can now "connect the dots". The new Program class looks like this:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
using (TrayManager trayManager = new TrayManager())
{
TrayOnlyApplication app = new TrayOnlyApplication();
app.StartupNextInstance += (s, e) => trayManager
.SetToolTipText(e.CommandLine.Count > 0 ? e.CommandLine[0] : "<no value given>");
app.Run(args);
}
}
}
You'll note two changes:
In addition to the TrayManager, which handles the NotifyIcon, we now also create the TrayOnlyApplication object, subscribing to its StartupNextInstance event so that we can receive the command line arguments given to any new instance, and use that to set the Text property of the NotifyIcon object (by passing that to the method created specifically for that purpose).
Instead of using Application.Run() to run the require message-pump loop to handle window messages, we use the Run() method our TrayOnlyApplication class inherited from the WindowsFormsApplicationBase class. Either of these methods handle message pumping while the program is running, and return control to the caller when the Application.ExitThread() method is called, so both approaches to message pumping work with the code in the TrayManager.
Now, the above example is simply a slight modification of the original version that didn't enforce single-instance operation. You might notice that it has the arguable deficiency that it always creates the tray icon, whether or not it's the first instance to run. Subsequent instances will run, create the tray icon, then immediately dismiss the icon and exit.
The WindowsFormsApplicationBase provides a mechanism to avoid this, the Startup event. While the StartupNextInstance event is raised in any instance of the application that is run when an instance already is running, the Startup event is raised only when no other instance is already running. I.e. in the instance where you actually want to do things, like show the tray icon.
We can take advantage of that event to defer creation of the NotifyIcon until we know whether we actually need it or not:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
TrayManager trayManager = null;
TrayOnlyApplication app = new TrayOnlyApplication();
// Startup is raised only when no other instance of the
// program is already running.
app.Startup += (s, e) => trayManager = new TrayManager();
// StartNextInstance is run when the program if a
// previously -run instance is still running.
app.StartupNextInstance += (s, e) => trayManager
.SetToolTipText(e.CommandLine.Count > 0 ? e.CommandLine[0] : "<no value given>");
try
{
app.Run(args);
}
finally
{
trayManager?.Dispose();
}
}
}
Note that here, we need to write the try/finally explicitly instead of using the using statement, because the using statement requires initialization of the variable when it's declared, and we want to defer initialization until later, or never, depending on which instance is being run.
(Unfortunately, there's no way to defer creation of the dummy window in the TrayOnlyApplication class, since it's required just to call the Run() method, which requires a valid Form object be already set, and the determination as to which instance is being run happens in that call, not before.)
And that's all there is to it. The above shows, clearly I hope, exactly how the single-instance application techniques available to you directly solve the problem you are asking for help with. By providing a mechanism for a newly-run instance of your program to communicate the command line arguments passed to it, to the already-running instance of the same program, that newly-run instance can cause the already-running instance to perform whatever work it needs to (such as changing the tool-tip text for the tray icon, for example).
Naturally, any similar mechanism will achieve the same result. The only important thing is to have the newly-run instance detect an existing instance, and communicate with it. It just happens that the WindowsFormsApplicationBase class provides that functionality pre-made. There are lots of other ways to do the same thing, each with their own pros and cons.
A little new to C#, and approaching something beyond me. Apologies for length.
I have a Windows Form application in Visual Studio C# Express, using the default classes VS spawns. I want to start and stop a Marquee style progressBar from a class other than the default Form1 in which it is declared.
These seems surprisingly difficult, I am sure I am missing something important.
My project has the usual classes that Visual Studio auto generates:
Form1.cs, Form1.Designer.cs , Program.cs .
I added myClass.cs that wants to talk the load bar.
I add progressBar1 bar to my form using the designer, setting Style:Marquee.
In Form1.cs' Form() constructor, I write
this.progressBar1.Visible = false;
This works. Intellisense 'sees' progresBar1.
code in Form1.cs can see and control progressBar1 declared in Form1.Designer.cs.
this makes sense to me.
But the functions which need to start and stop the load bar must live in myClass.cs.
I want to be able to code like this, within myClass.cs:
public void myFunction(){
Form1.progressBar1.visible=true
//do stuff that takes a bit of time
Form1.progressBar1.visible=false
}
This does not work. Intellisense cannot 'see' progresBar1 when typing code in myClass.cs.
In fact, intellisense cannot 'see' anything in Form1.cs from within myClass.cs.
No public propeties or functions added to Form1 ever become visible to intellisense.
This does not make sense to me, I am confused.
This seems like something you would want to do often and easily.
Some searching indicates that this blocking of external access to Form controls is by design. Something to do with 'decoupling' your logic code from GUI code, which makes sense in principal.So clearly there is an expected approach, yet an clear example is hard to find. I can only find examples of loadbars controlled from entirely within the Forms that declare them, or terse half-examples about creating and registering Events or using Invoke or other things I know too little about. There are many apparent solutions but none that I can see clearly apply to me, or that I am able to implement, in my ignorance.
I think I could do it if my Form were an instance.
[EDIT] nope. instance or not, Form1 controls never become exposed outside of Form1.cs
So, How do I to start and stop a Marquee style progressBar from a class other than the default Form1 in which it is declared, in the proper way?
Is there a clear and useful example somewhere?
You can't access your properties this way:
Form1.progressBar1
because Form1 is a type (not an instantiated object). The only methods or properties you can access with this approach have to be marked as static.
To answer your question of how to communicate, you probably want to use the event approach that you mentioned. First you need an event in your logic class:
public event Action<int> UpdateProgress;
Which is called just like a function:
if (UpdateProgress != null)
UpdateProgress(10);
This declares a new event using the Action generic delegate, which means the listening function has to return void and take one int as a parameter.
Then in your forms code, you'll have:
MyClass logic = new MyClass();
private void SomeFunction
{
logic.UpdateProgress += UpdateProgressBar;
}
private void UpdateProgressBar(int newProgress)
{
progressBar1.BeginInvoke(new Action(() =>
{
progressBar1.Value = newProgress;
}));
}
This creates a new instance of your logic class, and assigns the function "UpdateProgressBar" to be called whenever your logic class raises the UpdateProgressBar event. The function itself uses Dispatcher.BeginInvoke because your logic class is likely not running on the UI thread, and you can only do UI tasks from that thread.
There is a lot going on here, so please let me know if I can clarify anything for you!
I would create a model that has properties matching your form, and pass that around.
So you would make a new class like this...
using Windows.Forms;
public class Form1Model {
public ProgressBar progressBar { get; set; }
}
Then when you want to get to your other class holding that function you would create an instance of Form1Model, fill it, and call your function
var fm = new Form1Model {
progressBar = this.progressBar1;
};
otherClass.MyFunction(fm);
now you would have to change your function to accept the new model
public void MyFunction(Form1Model fm){
// do stuff
}
Another option is just making the function take an instance of the form, and not creating a model, but then you are going to be passing a lot of extra bits you probably won't care about
public void MyFunction(Form1 form){
// do stuff
}
Then on your form you would call the function like this
otherClass.myFunction(this);
I would recommend the first way over the second, you can control what data is being passed around
You are trying to access the type Form1 instead of the forms instance. I'll show you, how you can access the instance below.
I assume that Form1 is the applications main form that stays open as long as the application runs. When you create a WinForms application VS creates this code in Program.cs:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
A simple way to make your main form accessible throughout the application is to make it accessible via a public static property. Change the code like this
static class Program
{
public static Form1 MainForm { get; private set; }
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
MainForm = new Form1();
Application.Run(MainForm);
}
}
In Form1 create a property that exposes the progress bar's visibility:
public bool IsProgressBarVisible
{
get { return this.progressBar1.Visible; }
set { this.progressBar1.Visible = value; }
}
Now you can make the progress bar visible from any part of the program like this:
Program.MainForm.IsProgressBarVisible = true;
Another way of accessing the main form is, since it is always opened as the first form:
((Form1)Application.OpenForms(0)).IsProgressBarVisible = true;
However, it requires the form to be casted to the right type, since OpenForms returns a Form.
And don't forget: A Form is just a class like any other class. You can do almost everything you can make with other classes. So, communicating with forms is not very different than communication with other objects, as long as you are not using multithreading.
I'm new to C# (switching from Java) and i'm having a bit of trouble understanding GUI in C#
Ill just paste the Code i have and let that explain the most part.
Main Class:
Frame frame;
keepRunning = true;
public GraphicsComponent()
{
frame = new Frame();
frame.Show();
}
public void run()
{
while (keepRunning)
{
Console.WriteLine("Running");
}
}
public static void Main()
{
GraphicsComponent gameComponent = new GraphicsComponent();
gameComponent.run();
}
using the frame.Show() method, it appears and disappears for a quick moment. but the "running" loop is run.
The other way i have seen is another method called ShowDialoge(), that one keeps the window open but blocks the rest of the code from running until it is closed.
The way i want to use it is basically how GUIs work in Java. Where i can reference an object (and it's components) as needed in the rest of my code.
Thanks heaps!
Edit: There is alot of confusion, so here is my Frame class:
public partial class Frame : Form
{
public Frame()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
}
A normal way to kick off a winforms application is by file->new winforms project. WHen you do this you get "Program.cs", which contains your Main method - the entry point into your application. From there you have code like this:
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new ConfigForm());
}
In this example I kick off a new "ConfigForm"" that is a Form, and contains in it's ctor some code that looks like this:
public ConfigForm()
{
InitializeComponent();
// Other init work here
}
I create the form by right-clicking in the project and adding a new form.
You might want to look into the Application.Run method, see here. You can specify a "Main Form" which is going to be the main form that runs for the duration of the application, and when closed ends the application, or you can specify other options if you want. Perhaps the simplest solution is to start a main form, and since the form is live for the duration of the application, you can kick off other long-running code inside that form. If it's code that you want to be executing all the time performing some sort of background operation then you might want to fire it off in it's own thread. However, threading is hard so if you're new to c# / .net I'd try to stay away from threading unless you need it.
Can you exit an application before the constructor is finished and the main form is loaded?
At startup, I have a loading screen that displays before the main form is loaded. The loading screen is displayed from the constructor before the constructor has finished.
I do something similar with an exit screen by using a variable between the main form and the exit screen. I have an application exit in the main form if the exit screen returns true.
Finally, should all the thread/class/loading/program setup be done in the main constructor or am I doing it wrong?
Update:
I mean after the program.cs and in the static main
namespace app
{
public partial class app1 : Form
{
public app1()
{
InitializeComponent();
// open loading screen
// initialize vars
// create objects
}
// form opens when app1() finishes
Is app1() the right place to initialize everything?
If I try to send a "close" message back from the loading screen before app1() is finished, it doesn't work - the process still runs even though nothing is open.
I've found that if I try to kill my application from the main form constructor when I still have the splash screen showing on a different thread (which looks similar to what you are doing), that Application.Exit() does not work, but Environment.Exit(-1) does.
try this,
public partial class MyForm : Form
{
public MyForm()
{
if (MyFunc())
{
this.Shown += new EventHandler(MyForm_CloseOnStart);
}
}
private void MyForm_CloseOnStart(object sender, EventArgs e)
{
this.Close();
}
}
it will work well...
Which main constructor of which class?
Are you talking about the static method Main that has a default location in the Program class?
You use that method to do initialization that needs to occur before you open any windows on screen.
Obviously, if you need to use a loading screen, you will probably want to move some code somewhere else, as you need a message loop around forms, and the message loop will block until your form closes.
If you return from the Main method before you open any form, then no form will be shown obviously.
Having said all that, I feel your question is a bit vague and I'm pretty sure I didn't understand exactly what it is that you're asking.
First and foremost, Main is not a constructor, it's just a static method.
When main thread ends:
background threads are "killed/abandoned"
foreground threads (the default when creating threads) are waited till they finish.
you can break constructor only via throwing an exception. To do that surreptitiously, throw you own specific exception.
class ConstructorAbortedException : Exception { }
class Foo
{
public Foo()
{
if(goesWrong)
{
throw new ConstructorAbortedException();
}
}
}
void Bar()
{
try
{
Foo f = new Foo();
}
catch(ConstructorAbortedException)
{
//..
}
}
As jontsnz answered, the code with
Environment.Exit(-1)
works fine in the constructor, but this causes the application to throw an "Application Hang" event, which can be seen as an error in the Windows Event Viewer. Using
Environment.Exit(0)
exits without registering an error though, so I prefer that one.