Inside the App.xaml.cs of my WPF application, starting from the entry point Main() which simply looks like this:
[STAThread]
public static void Main()
{
var app = new App();
app.StartApp();
}
I experience some unexpected behavior when either of the two MessageBox's are uncommented.
protected void StartApp()
{
// uncomment this = the messagebox will show and return after 'okay' is clicked.
// The application will never start even after `this.Run()` is called?
//MessageBox.Show("Hello");
this.InitializeComponent(); //auto generated code
this.StartupUri = new Uri("MainWindow.xaml", UriKind.Relative);
// uncomment this = the messagebox will show and simultaneously the application will run().
// The line below will only be hit on termination of the application
//MessageBox.Show("Hello");
this.Run();
}
At a guess, MessageBox.Show is doing something funky with the current Application context, as putting MessageBox.Show on the very first line of Main() works exactly as expected.
Application.Run() besides WPF-specific stuff calls Dispatcher.Run().
Last one runs a window message loop.
Same does native message box inside MessageBox.Show.
Hence message box calls before Application.Run() should be avoided.
Task.Run(()=>MessageBox.Show("Hello")).Wait() will produce the 'expected' result - i.e. it's message pump will not affect the execution of the calling Application.
Related
This code doesn't show the Window, it just closes automatically. Why is this happening?
class Program
{
[STAThread]
static void Main(string[] args)
{
var window = new MainWindow();
window.ShowDialog();
}
}
I know that you can fix it adding a new Application.Run(window) but I would like to know why it has this behavior and why you have to invoke the Run method over the window instance.
EDIT:
Extending the previous question, I've noticed that this code will work:
Create a new WPF Application.
Go to App.xaml and delete the StartupUri
Modify the App.xaml.cs overriding the method OnStartup
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
var window = new MainWindow();
window.Show();
}
}
With this, the window remains open. What's going on under the hood?
Microsoft Windows programs are event-based. They act upon messages that the operating system posts to the main thread of the application. These messages are received from the message queue by the application by repeatedly calling the GetMessage (or PeekMessage) function in a section of code called the "event loop."
When Run is called, Application attaches a new Dispatcher instance to the UI thread. Next, the Dispatcher object's Run method is called, which starts a message loop to process windows messages. Finally, the Dispatcher object calls the Application object's OnStartup method to raise the Startup event.
Without a message loop, the application is unable to support the UI.
I tried to show a winform with the code below but it opens and immediately closes.
I couldn't understand the reason for this.Any ideas?
[STAThread]
static void Main()
{
try
{
AppDomain.CurrentDomain.UnhandledException += AllUnhandledExceptions;
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException);
Test testWin = new Test();
testWin.Show();
}
catch (Exception ex)
{
Logger.Error("Main : " + ex.Message, typeof(Program));
}
}
Its works fine if I replace testWind.Show() with Application.Run(testWin).
Application.Run runs the message loop which basically handles UI events etc until all the visible windows have shut. The method blocks until the message loop has shut down.
You need that message loop to be running in order to keep the UI up, basically - whereas Show() will just display the window, but not run any kind of message loop itself, and not block - do the Main method completes, and the application terminates.
You should use ShowDialog method instead.
Test testWin = new Test();
testWin.ShowDialog();
I have a C#/TCP/Winform app that's been running for quite some time, but one of my users has discovered an issue that I can replicate easily, but that I can't seem to solve.
If the app is open on Windows 7 and the user then changes any option in their screensaver settings - be it the screensaver being used or the time - the app freezes and the UI becomes non-responsive. Clicking anywhere on the form just gets the system "ding."
When the app is run through Visual Studio in debug mode, the problem ceases to exist, but once out of the confines of VS, goes back to freezing.
After some tinkering and testing, I seem to have narrowed down my problem to a System.Threading.Timer that runs once every second. I've been steadily paring down what the timer does and discovered that even if the timer's event does nothing, it still locks the app. If I disable the timer in the code or cancel the timer in the app prior to changing the Screensaver settings, then the app will return to functional after a screensaver change (though it still seems to freeze for about 2-3 seconds).
This code here, seems to be all that is necessary to make the app freezable (within the WinForm code):
/// <summary>
/// Starts the countdown timer for unit alerts
/// </summary>
private void startCountDownTimer()
{
Object timeState = new object();
this._timerCall = new System.Threading.TimerCallback(this.countDown);
this._countdownTimer = new System.Threading.Timer(_timerCall, timeState, 0, 1000);
}
/// <summary>
/// Invokes the countdown logic for unit alerts
/// </summary>
/// <param name="state"></param>
private void countDown(Object state)
{
// REMOVED AND STILL FREEZING
}
Note that this freeze happens even with the contents of countDown commented out so that the timer is doing nothing other than firing once per second.
If I launch process and then attach a remote debugger to it, there is nothing in the output that indicates that anything is wrong with the application. The form actually still fires events like "Activated":
*** MAIN WINDOW ACTIVATED ***
*** MAIN WINDOW ACTIVATED ***
However nothing else seems to be firing and the application has to be either killed or shut down via EndTask. If EndTask is used while the debugger is still attached, I suddenly get errors:
A first chance exception of type 'System.InvalidOperationException' occurred in System.Windows.Forms.dll
===================================
ERR: Invoke or BeginInvoke cannot be called on a control until the window handle has been created.
at System.Windows.Forms.Control.MarshaledInvoke(Control caller, Delegate method, Object[] args, Boolean synchronous)
at System.Windows.Forms.Control.BeginInvoke(Delegate method, Object[] args)
at System.Windows.Forms.Control.BeginInvoke(Delegate method)
at Wcsg.UI.Windows.CadClient.client_MessageReceived(TcpMessageReceivedEventArgs mrea) in C:\Users\---------\Documents\Visual Studio 2010\Projects\Dispatch-DEVELOPMENT\CadClient\Forms\CadClientForm.cs
at Wcsg.Net.Tcp.WcsgTcpClient.processStream(Int32 count)
at Wcsg.Net.Tcp.WcsgTcpClient.performSocketRead(IAsyncResult ar)
---------------------
The errors that I do finally get would seem to be linked to the closing of the form while it finally gets around to processing the messages on the socket.
I'm looking for any sort of direction to look here.
* EDIT *
I was asked about the Main method in the program when the expected workaround (see answer) didn't work. Here is the Main code:
[STAThread]
static void Main(String[] args)
{
// check for other running CadClients
bool createdNew = _mutex.WaitOne(TimeSpan.Zero, false);
if (createdNew) // first-run, launch Status Monitor on load
{
List<String> newArgs = new List<string>(args);
newArgs.Add("-SM");
args = newArgs.ToArray();
}
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
AppDomain currentDomain = AppDomain.CurrentDomain;
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
// try to catch issue 13445 -- see testing notes
CadClient cc = new CadClient(args);
CadExceptionHandler ceh = new CadExceptionHandler(ref cc);
currentDomain.UnhandledException += new UnhandledExceptionEventHandler(ceh.CurrentDomain_UnhandledException);
Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(ceh.Application_ThreadException);
Application.Run(cc);
}
* EDIT *
I should probably add the Splashscreen code as well:
private void showSplashScreen()
{
WaitCallback wcb = new WaitCallback(doSplashScreen);
ThreadPool.QueueUserWorkItem(wcb);
}
private void doSplashScreen(object state)
{
if (this._splash == null)
this._splash = new SplashForm(this);
this._splash.FormClosed += new FormClosedEventHandler(_splash_FormClosed);
this._splash.Show();
while (this._splash != null && !this._splash.WorkDone)
Application.DoEvents();
this._splash.Close();
}
The method showSplashScreen() is called within the main form's constructor - originally before and now after the InitializeComponents() call. The splash screen displays updates its display while the main app validates some security. Then it turns into a login screen and then displays more udpates while the main app loads data from the server. Once the main form indicates (via event) that it has completed its work, the SplashScreen is closed.
Used the comment from #HansPassant and found that the showSplash method for our splash/login screen was not being called before Application.Run, but WAS being called before our main form's InitializeComponent method. Moved this.showSplash to the line immediately below InitializeComponent() and recompiled and the problem seems to be gone.
I've got a mono app written in c# and executed on a Mac using "mono myapp.exe"
The app itself is a "Windows Application" when viewed from the project properties, but it doesn't always show a window. In program.cs, there is a static Main:
static void Main(string[] args) {
UserClient client = new UserClient();
client.Start(args);
}
public class UserClient {
public void Start(string[] args) {
// Talk to server, listen for instructions, etc.
....
// Launch the "Stay Alive" thread
// Just a thread that Sleeps/Loops watching for an exit command; mainly used to keep the process alive
}
}
Inside the UserClient's Start method, there is a piece of code that continuously monitors a server which gives it instructions to do things. One of the things it does is optionally displays a message using a windows form.
When the server instructs the process to display a message, it instantiates a form, displays it using frm.ShowDialog() and then after 30 seconds, a timer on the form runs Close() and the frm then gets disposed. However, when this happens, on my Mac I see an application title bar saying "mono" and a new icon on my dock bar for the mono app. After about 2 minutes the mono process in Activity Monitor shows "Not Responding." This eventually will prevent the user from logging out, shutting down, etc. (because Mac OS can't kill mono gracefully).
ON THE OTHER HAND... if the server never tells the process to display that form, everything runs fine and dandy: a dock icon never shows up (which is good!), mono title bar never shows up and the mono process continues to run happily, not preventing the system from shutting down or rebooting.
Anyone experienced this or have ideas on what's causing it? My guess is that it's a new GUI thread being created by the form which isn't ever being shutdown and is somehow causing a lockup, though I'm unsure of how to handle it.
Thanks for any suggestions.
Update:
Here's some code to easily reproduce and see this happening. I realize that this seems kind of "non-standard." Having said that, the below works perfectly in a Windows environment and provides the desired result of not showing an icon in the task area except when showing a message. Currently, using Application.Run and simply doing frm.ShowDialog() produce exactly the same result.
In the end what we need is to be able to display the form, then destroy the form and any associated icon from the dock. I suspect the GUI is starting a thread which isn't ever being disposed, which is why the dock icon remains. Is there a way to make sure the GUI thread is taken care of?
static class Program {
static void Main() {
StartupClass s = new StartupClass();
s.start();
}
}
public class StartupClass {
Thread stayAliveThread;
public void start() {
// Stay alive thread
stayAliveThread = new Thread(stayAliveLoop);
stayAliveThread.Start();
// This shows a form and would normally be used to display temporary and brief messages to the user. Close the message and you'll see the undesired functionality.
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
Application.Exit();
Application.ExitThread();
}
/// <summary>
/// Keep the app alive.
/// </summary>
private void stayAliveLoop() {
while (true) {
Thread.Sleep(10000);
// In the real project this method monitors the server and performs other tasks, only sometimes displaying a message.
}
}
}
I feel I'm missing several things. Most notably
[STAThread]
static void Main(string[] args) { //....
Also see this answer: Windows Forms and ShowDialog problem
I can't see anything like initializing message loop for windowed application. I.e. in windows forms case something like Application.Run(). If you do not have it, no wonder application freezes. In any case, posting more code could be helpful, as stated in comment.
In the end, I couldn't resolve this. I created a process that launched another app which displayed the message form. Not really a true answer, but the solution I had to go with.
Is it possible to call Application.Run, but to not pass a form parameter, or is there an alternative if there’s no form to call?
The Run method doesn’t seem to have any overloads that don’t accept a form.
For example, if I wanted to instantiate a class first, and then have that call the form, is there way to do the equivalent of:
Application.Run(myClass);
Just to clarify, I do still want the functionality that .Run() provides. That is, establish a loop to keep the application running, but instead of tracking a form, track a class or other object.
This is relating to the compact framework initially. I assume that's why the Run method doesn't have the overload I was looking for.
The Run method doesn’t seem to have any overloads that don’t accept a form.
Uh... http://msdn.microsoft.com/en-us/library/ms157900.aspx
Application.Run Method
Begins running a standard application message loop on the current thread, without a form.
public static void Run()
I'm not clear whether you want to do:
You want to load your form somewhere else other than the Main()
Or Run a console or service application with no UI.
For (1):
static void main()
{
//Your program starts running here<<<
//Do some stuff...
FormRunner a = new FormRunner();
a.RunForm();
} // << And ends here
class FormRunner {
public void RunForm() {
Application.Run(new Form());
}
//You could call which ever form you want from here?
} // << And ends here
What you need to know is your program starts from the first line of the main and ends at the last. However, when you call Application.Run(FORM) it loads up a windows message loop for that form. Its a special loop that keeps the program still in the main and waits for events (they're called Windows Messages in win32 API)
And so the program does not end until the user clicks the close button. When this happens, thats when your program actually will return from its Main.
(2) So now if you just want a pure console app with no forms:
static void main()
{
AcceptInputs()
DrawScreen()
//Do something else.
//Make sure your flow stays within the main
} // << Once you come here you're done.
void AcceptInputs()
{
while(true) {
//Keep accepting input
break; // Call break when you're done. You'll be back in the main
}
}
I hope that helped.
You can use the overload of Application.Run that accepts an application context as its only parameter. An ApplicationContext is basically just a class that you can inherit from and add any functionality you like. See the example in the link for more information.
using System;
using System.Windows.Forms;
static class Program
[STAThread]
static void Main() {
Application.Run(new myClass());
}
internal class myClass : ApplicationContext {
public myClass() {
Application.Run(new myWindow());
}
}
}
The problem here, though, is that something will have to call this instance of myClass and tell it to exit or else the program will just keep running even after all forms are closed. And calling ExitThread() in the constructor is ignored.