Recently I'm writing some code to display unhandled exceptions of the winforms app.
I want those exception-display-windows to be TopMost.
So I add an event handler to Application.ThreadException
. The handler creates a new thread, opens a new form with TopMost
attribute set to true
.
Then I realize, new windows can't be TopMost even if their TopMost
attribute is true
. What's more, if any MessageBox
was shown, subsequent new windows regain the ability to be TopMost!
There already is a post discussing this problem: TopMost form in a thread? But that answers still can't make my windows TopMost. Besides, I want to know why TopMost
is valid after a MessageBox
is shown.
Here is my minimal issue demo:
using System;
using System.Threading;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.ThreadException += (o, e) => handleException();
Application.Run(new Form1());
}
static void handleException()
{
// before messagebox
doDisplay(); //Count:1
doDisplay(); //Count:2
doDisplay(); //Count:3
// Delay a while for the display threads to run
Thread.Sleep(300);
// show messagebox
if (MessageBox.Show("It doesn't matter you choose YES or NO",
"Message", MessageBoxButtons.YesNo) == DialogResult.No)
; // empty statement, just show msgbox
// after messagebox
doDisplay(); //Count:4
doDisplay(); //Count:5
doDisplay(); //Count:6
}
static int count = 0;
static void doDisplay()
{
Thread t = new Thread(new ThreadStart(() =>
{
Form f = new Form();
f.TopMost = true;
f.Text = "Count: " + ++count;
f.ShowDialog();
}));
t.IsBackground = true;
t.Start();
}
}
public class Form1 : Form
{
public Form1()
{
Button b = new Button();
b.Text = "throw!";
b.Click += (o, e) => { throw new Exception(); };
this.Controls.Add(b);
}
}
}
Output: window with Count: 1/2/3 aren't topmost, window with Count: 4/5/6 are topmost.