I am making a "Main()" function in a WindowsForms Application in C#. I have been following a book on Game programming in C#. When I run the examples everything works, but when I try to make my own version nothing works.
Here's the Main() function:
public void Main()
{
while (!gameOver)
{
// Non timed code:
int ticks = Environment.TickCount;
if (ticks > lastTick + 16)
{
lastTick = ticks;
//Timed (60FPS) code here:
Application.DoEvents();
}
}
}
When I put this inside the "Form1_Load" function the form does not even show when I start the program, while not giving any errors or warnings (the same thing is done in the examples, which runs). If I move my "Main()" to for example "MouseClick" and the form shows and when I click is the function starts running as it should.
I am really out of ideas as to why this happens. Am I missing something really obvious here?
A form's Load event is not exactly the best place to start a game-loop. There are two basic reasons that Load will be fired. The "good" way is when it happens in response to the Show() call, normally present in the Program.Main() method. Your game-loop will work.
The "bad" way is when code in your form constructor requires the form's Handle property to be valid. That forces Winforms to create the native window and that triggers Load. That still usually comes to a good end, the odds get lower the more convoluted it gets.
That will go wrong in your case since the Load event handler doesn't return. Which means that the constructor cannot complete. Which means that the window cannot become visible. Which means that "gameOver" can never become true. Game over. You diagnose this with the debugger, set a breakpoint on the Load event handler and look at the Call Stack window. With the expectation that you'll see the statement in the constructor that caused the problem.
Last but not least, be very wary of this failure mode.
The real fix is to put this code in the right place. Which is in the Program.Main() method. Roughly:
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
// Application.Run(new Form1()); Not this anymore
var window = new Form1();
window.Show();
// Your game loop here
//...
}
You could try putting the loop logic in a static void method and executing it on a thread
that way it will go about its merry way and the form will go ahead and load
Related
So using windows form builder, I have created a new form with textbox in it, calling this form as LogForm.cs, this form/class has a method called log(string text).
In my main form class (Form1.cs), I have created an instance of that form.
LogForm logForm = new LogForm();
logForm.log("Logger has started...");
and it show fine on the LogForm textbox. But when I call logForm.log("Some logging info...") On my code inside a thread, it somehow makes my application crash.
How do I deal with this? Please help me demostrate a small code.I am fairly new to C# and programming as a whole so I hope you consider.
Use/call this function in LogForm.log (btw methods in C# are usually capitalized).
private void SetText(string text)
{
Action set = () => yourTextBox.Text = text;
if (yourTextBox.InvokeRequired)
{
yourTextBox.Invoke(set);
}
else
{
set.Invoke();
}
}
If it cannot be set from the current thread yourTextBox.InvokeRequired will be true and the function will work it out. Otherwise it just sets it directly.
Inspiration from this answer at possible duplicate.
Since you are saying the problem persists I'll show a bit more code and try to expain it further.
First of all, I edited the SetText method. I added the private modifier since this function is not indended to be called anywhere outside of LogForm. I also added the curly brackets since that's my preferred style and it also makes sure that the if-statement behaves as expected.
public void Log(string message) {
SetText(message);
//do stuff
}
Both of these methods (Log and SetText) are placed inside the LogForm class. You can now call logForm.Log("Logger has started..."); from any thread as long as your form (containing the textbox) is already initialized. This usually happens in the constructor by calling InitializeComponent(); on the first line.
Without knowing more about your code this is probably as far as I can help you.
I am creating a Form when a certain event occurs. I put this created Form into a static member of the class where it is created. I debugged the code and everything works fine but the Form stays blocked and the user can't do anything in this window. It just appears with a loading animation (see picture). So nothing in the opened window is clickable, you can't even close it.
class CallManagementObserver : CallObserver
{
private static FrmIncomingCall frmCurrentCall;
public CallManagementObserver()
{
}
public void callChangedEvent(CallEv[] events)
{
foreach (CallEv currentEvent in events)
{
switch (currentEvent.getID())
{
case TermConnRingingEv.ID:
// Incoming call
frmCurrentCall = new FrmIncomingCall(currentEvent);
frmCurrentCall.Show();
frmCurrentCall.Update();
break;
case CiscoCallInfoChangedEv.ID:
// User accepted external call on terminal
frmCurrentCall.Close();
break;
case TermConnActiveEv.ID:
// User is in call
frmCurrentCall.Close();
break;
case ConnDisconnectedEv.ID:
// Caller has hung up
frmCurrentCall.Close();
break;
default:
break;
}
}
}
}
}
As you can see above I wrote my own Form class whose code is here:
public partial class FrmIncomingCall : Form
{
Call incomingCall;
CallEv currentEvent;
public FrmIncomingCall(CallEv currentEvent)
{
InitializeComponent();
this.currentEvent = currentEvent;
this.incomingCall = currentEvent.getCall();
}
private void initGui()
{
Connection[] callConnections = incomingCall.getConnections();
Address caller = callConnections[1].getAddress();
lblIncomingCallSource.Text = caller.getName();
}
private void btnAcceptCall_Click(object sender, System.EventArgs e)
{
TermConnEv termConnEv = (TermConnEv)currentEvent;
TerminalConnection termConn = termConnEv.getTerminalConnection();
termConn.answer();
}
private void frmIncomingCall_Load(object sender, System.EventArgs e)
{
initGui();
}
}
When I show the Form via ShowDialog() it is usable but the program stops (since this is what dialogs are made for I guess).
Any ideas what I'm doing wrong? Nothing freezes, the program is running correctly.
Well, your application is poorly designed... It seems that you have no idea of what multithreading is and why you should use it.
If the application hangs forever, then either there is a deadlock (something like the dialog wait on the calling system and the calling system wait on the dialog).
As I have no idea what CallEv is and how it is intended to be used.
Well, if the calling system works and the UI is never updated, then obviously, you never let the UI have time to be updated because your UI thread is 100% of the time using the calling system or waiting on it.
That means that the calling system should probably be used from another thread and that you should have some communication between both threads...
It might also be possible that the calling system might be used in many different ways (as it would be the case for serial port and TCP communication) where one could use what fit most with his application.
Another problem with your code is that when you close a dialog, as far as I know it cannot be used anymore without recreating the dialog as the dialog would be disposed... So you would need to set the formCurrentCall to null and update any affected code. Alternatively, you might hide the form instead and show it again when required.
In any case, it is hard to help you because we don't have any idea of what is CallEv and other classes or events in your code. Also, we have no idea which code is executing when the UI is not responding (or updated). So the question do not have enough informations. In fact, such problem are way easier to debug using a debugger as it is far easier to see what code is run and which line of code take time to execute or even to see which code is not executed.
I'm playing a little bit with some C# Winforms/WPF code and just stumbled upon something strange.
Let's say I have a code like this:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DoSomething();
// something more if everything worked okay
}
}
What puzzles me is that I cannot simply close the application from the method DoSomething before the constructor finishes its job. If anything during the execution of DoSomething fails, I need to close the application immediately; however, it just keeps running, executes the part // something more... and THEN closes, but that's way too late for me.
I have to put the code for closing the form inside the constructor itself with a following return; and then it works, but I don't really find that an acceptable solution. I'm trying to move such validation logic from the constructor to my methods.
I've tried things like:
public void DoSomething()
{
Close();
}
and
public void DoSomething()
{
Application.Current.Shutdown();
}
But it doesn't seem to work. Yes, both codes do close the application, but only after a fully finished constructor code.
Why would I need such a thing? Well, because at startup I need to check for various things, like availability of the connection and hardware, validate the user etc, and if anything fails, there's no point of executing more code.
I tried the same principle with Winforms and WPF (hence the tags) — works the same way.
Can anybody provide an explanation or a solution?
Just try using Environment.Exit(-1) in your situation and all will be good.
ADDED: This is the best reference i can get for you.
Difference between Application.Exit vs Application.Shutdown vs Environment.Exit
Application.Exit() is for exiting a windows forms application in a graceful way. Basically, it stops the message pump, closes all windows and lands you back in the Main() method just after the call to Application.Run(). However, sometimes it doesn't appear to work - this is usually because there are other foreground threads (apart from the UI thread) still running which are preventing the thread from ending.
Application.Shutdown() is (broadly) the equivalent of Application.Exit() in a WPF application. However, you have a bit more control as you can set the ShutDownMode so that the application shuts down when the main window closes, the last window closes or only when this method is called.
Environment.Exit() kills all running threads and the process itself stone dead. This should only be used in WF or WPF as a last resort when the more graceful methods are not working for some reason. It can also be used to make an abrupt exit from a console application.
Another Reference: How to properly exit a C# application?
You can always ignore your fellow developers and just use Environment.FailFast()
But really - don't. If you have critical things to do, S.A verifying the serial port is connected to the nuclear power plant, just do it prior. There's no rule forcing you to Application.Run(...) as soon as Main() is called.
There have already been posted viable solutions for your problem.
Just to answer your follow-up question: the reason why methods like Close() and Shutdown() do not immediately exit your application is that both just push messages into the application's message queue. They are only processed after MainWindow's constructor finished and code execution returns to the message processing loop, maybe even after some other still pending messages in the queue have been handled too.
On the contrary, methods like Environment.Exit() or Environment.FailFast() are kind of hard-core os functions leading to more or less immediately killing the process.
A workaround would be to throw a exception and handle it in application.UnhandledException
Define an Exception class:
public class InitializationException : Exception
{
public InitializationException()
{}
public InitializationException(string msg)
: base(msg)
{}
public InitializationException(string msg, Exception inner)
: base(msg, inner)
{}
}
and change your code like this:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
try
{
DoSomething();
// maybe something more if everything went ok
}
catch( InitializationException ex )
{
// log the exception
Close();
}
}
public void DoSomething()
{
if (notSomethingOK)
throw new InitializationException( "Something is not OK and the applicaiton must shutdown." );
}
}
This is a clean and maintainable solution.
System.Windows.Forms.Application.Exit();
Conceptually such things should not be used in class constructors. Constructor is somewhat made for instance initialization with starting state and not the actual things may happen (like exceptions, message boxes, etc).
Don't forget that you can just return; from constructor, if you need to break its execution. This is better tactic (most times you don't need to just shutdown application on error without displaying some text).
There are "window shown", "visibility changed", "loaded" and many other events in C# on Windows/WPF, that you can override virtually or add as an event handler. Initialize your form/app there.
They're normal methods so all works as expected. You can try throwing exceptions that your application entry point (Main function) will just catch and ignore.
For WPF, check this:
- https://msdn.microsoft.com/en-us/library/system.windows.forms.application.setunhandledexceptionmode(v=vs.110).aspx.
When I close my C# application, I am getting the a windows sound that indicates an error. However, when I debug through the close process, I get all the way back up into the Program class...
It gets past Application.Run(..), exits the static void Main() function, and then makes the error noise.
Other than the noise there is nothing indicative of an error. I don't even know where to begin looking! Any ideas?
One thing that you could to in order to maybe get some information is to hook up event listeners for the AppDomain.UnhandledException and Application.ThreadException events. It's a long shot, but may provide some info. You could add the following in the beginning of the Main function to set them up, and have them show any exception info in a message box:
static void Main()
{
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(delegate(object sender, UnhandledExceptionEventArgs e)
{
MessageBox.Show(e.ExceptionObject.ToString());
});
Application.ThreadException += new ThreadExceptionEventHandler(delegate(object sender, ThreadExceptionEventArgs e)
{
MessageBox.Show(e.Exception.ToString());
});
// run your app
}
It only happens when you close your app or does it happen when you close any app?
My first thought would be that someone changed your windows sound scheme and set the close program sound to mess with you :).
Something is going wrong in the cleanup, that could be very hard to find. There are two ways to attack this:
Enhance the chances of detecting it while you're still in control (in Main) by wrapping everything in your Main in a try/catch and add some code after the Application.Run to get as much of the cleanup going as possible. A few things I can think of:
GC.Collect();
GC.WaitForPendingFinalizers();
Thread.Sleep(1000);
GC.Collect();
GC.WaitForPendingFinalizers();
Collect at least 2 times, maybe more. In the same spirit, add a few Application.DoEvents() in the OnClosing of the MainForm.
The other approach is more dependent on your code, to take a stab in the dark: look for all static fields/properties you can set to null and Disposable objects you can Dispose deterministically on Exit.
And all this in combination with Fredrik Mörks suggestion for the UnhandledException event.
Do you have any code that raises custom events? Could these processes still be running when the app tries to close in real-time?
Do you have any custom Dispose code that could be running at time of close?
At work we use DevExpress for the user interface. The first time a form employing a DevExpress control is opened there's a long pause (sometimes 15-20 sec on some clients). In Visual Studio i can see that tons of assemblies are being loaded during that phase. Is there a way to preload that assemblies into the AppDomain in the background on a thread that is spawned for example before the login screen pops up?
Another choice is to force the JIT to load the assemblies asynchronious instead of doing it by hand. The trick is to simply call the constructor of the control, so the Jit knows that it has to start compiling that particular code path. Usually that forces it to load all dependant assemblies. Just make sure to surround the call of the constructor by a try catch.
An example of how to do that at loadtime:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
PreJitControls();
Application.Run(new Form1());
}
private static void PreJitControls()
{
ThreadPool.QueueUserWorkItem((t) =>
{
Thread.Sleep(1000); // Or whatever reasonable amount of time
try
{
AssemblyPullingControl1 c = new AssemblyPullingControl1();
}
catch (Exception) { }
try
{
AssemblyPullingControl2 c = new AssemblyPullingControl2();
}
catch (Exception) { }
});
}
}
But you could also do something similar in the constructor of the login form, if that is a better time to do the pre-loading. Just move the PreJitControls method to the login form and call it from the constructor.
This will however force your users to always take that hit on start up.
In general this is a bad idea (if you have the hit at least defer it till you really need it). A case where it might help is to trigger the load if there is a strong chance that they are going to use the functionality in the near future but the system is otherwise idle. This can be very hard to do accurately though.
You might see whether any of the loaded assemblies are under your control and in the GAC. If so you could ngen them which may have a significant effect on the start up time of this aspect of your UI.
I'm not sure, but I am guessing that not the actual loading of the assemblies is the timeconsuming part - but probably the JIT compiling of the code path. Maybe you want to look at ngen. could be that it makes the performance problem go away. but be sure to understand the implications of that tool.
Links:
- http://msdn.microsoft.com/en-us/library/6t9t5wcf.aspx
- http://msdn.microsoft.com/en-us/magazine/cc163610.aspx
have a look at the Assembly.Load methods.
Gero
If you are trying to get your assemblies faster, why not have a look at NGEN for your code. Pre JIT everything in the background. This has pro's and con's though depending on what your app is doing.