简体   繁体   中英

BringToFront a form that is under an another thread while main UI thread is not responding?

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM