I have a legacy application, I cannot change the code that block the main UI thread, and I have to put a kind of message that say "please wait while the process is finishing" with a little animated gif.
I have created a form that will be running under it own thread, frmBusy.showmodal
and waiting for a signal to close itself, received by the main ui thread.
On that thread I have a timer set at 1 second to do the application.doevent
to prevent the ContextSwitchDeadlock
exception
this is working nicely.
the issue is if the client click on show desktop or alt-tab or do something that change the focus while it is not responding and the user alt-tab back to the application, the frmBusy
form is now hidden.
I have tried the frmBusy.BringToFront
, doesnt work.
I have tried the usual frmBusy.Actite
which work but steal the focus if the user actualy want to be somewhere else, no good.
I have tried the frmBusy.TopMost = true
/ frmBusy.TopMost = false
which work but if the user is actually on another application that form will be over that new application, no good.
is there a way to do what I want or is it simply impossible?
edit
Using Banana code, I implemented an example of the issue
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
this.WindowState = FormWindowState.Maximized;
Form2.InitDialog(this.Handle);
Thread.Sleep(60000);
}
}
public partial class Form2 : Form
{
bool TRunning = false;
IntPtr _f1Handle;
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
public static void InitDialog(IntPtr F1Handle)
{
Form2 F2 = new Form2(F1Handle);
new Thread(() => F2.ShowDialog()).Start();
}
private bool CheckIfForemost()
{
return GetForegroundWindow() == _f1Handle;
}
public Form2(IntPtr F1Handle)
{
TRunning = true;
_f1Handle = F1Handle;
InitializeComponent();
this.ShowInTaskbar = false;
}
private void Form2_Load(object sender, EventArgs e)
{
var sw = System.Diagnostics.Stopwatch.StartNew();
new Thread(() =>
{
while (TRunning)
{
Thread.Sleep(100);
if (CheckIfForemost())
{
InvokeIfRequired(this, () => this.TopMost = true);
}
InvokeIfRequired(this, () => this.TopMost = false);
InvokeIfRequired(this, () => this.Text = sw.ElapsedMilliseconds.ToString() + " " + GetForegroundWindow().ToString() + " " + _f1Handle.ToString ());
}
}).Start();
}
public static void InvokeIfRequired(Form control, MethodInvoker action)
{
if (control.InvokeRequired)
{
control.Invoke(action);
}
else
{
action();
}
}
}
you can have the frmBusy check every certain amount of time for the foremost window, and compare it's handle to your main form's handle, and if it fits then pop the frmBusy to front with TopMost=true
and disable it right away.
Here is a quick example that you can easily adapt to your project:
Form1
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Form2 F2 = new Form2(this.Handle);
F2.Show();
}
}
}
Form2
namespace WindowsFormsApplication1
{
public partial class Form2 : Form
{
bool TRunning = false;
IntPtr _f1Handle;
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
private bool CheckIfForemost()
{
return GetForegroundWindow() == _f1Handle;
}
public Form2(IntPtr F1Handle)
{
TRunning = true;
_f1Handle = F1Handle;
InitializeComponent();
}
private void Form2_Load(object sender, EventArgs e)
{
new Thread(() =>
{
while (TRunning)
{
Thread.Sleep(100);
if (CheckIfForemost())
{
this.TopMost = true;
}
this.TopMost = false;
}
}).Start();
}
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.