在移动和调整大小时,表单叠加层显示在表单后面

Form overlay showing behind form on move and resize

我已经设置了一个自定义控件作为加载叠加层,叠加层是一个带有图片框的表单,用于显示图像。

当叠加层显示它就位并且位于调用它的主窗体前面时,这看起来很棒。但是,当用户移动表单或调整表单大小时,表单会回到主表单。

当主窗体移动或调整大小时,覆盖窗体移动和调整大小没有问题,但在完成调整大小或移动后,窗体落后于主窗体。如何在不使用 TopMost 的情况下将覆盖表单返回顶部?

我使用

从主窗体调用以下代码
LoadingControl p = new LoadingControl(dataGridView1, this);
p.Show();

叠加形式:

using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;

public class LoadingControl : Form
{
    private Color BackgroundColour = Color.Black;
    private double BackgroundOpacity = 0.50;
    private Image LoadingImage = APPNAME.Properties.Resources.loading_120x128;
    private Form Mainform;
    private Control MainControl;

    public LoadingControl(Control parent, Form frm)
    {
        MainControl = parent;
        Mainform = frm;
        SetupForm();

        Size = parent.ClientSize;
        Location = parent.PointToScreen(Point.Empty);

        Mainform.Move += AdjustPosition;
        MainControl.SizeChanged += AdjustPosition;
    }
    private void SetupForm()
    {
        FormBorderStyle = FormBorderStyle.None;
        BackColor = BackgroundColour;
        Opacity = BackgroundOpacity;//0.50;
        ShowInTaskbar = false;
        StartPosition = FormStartPosition.Manual;

        PictureBox pbox = new PictureBox {Image = LoadingImage, Parent = this};
        pbox.Width = pbox.Image.Width;
        pbox.Height = pbox.Image.Height;
        pbox.Left = (Width/2) - (pbox.Width/2);
        pbox.Top = (Height/2) - (pbox.Height/2)-10;
        pbox.Anchor = AnchorStyles.None;
        Controls.Add(pbox);
    }

    public void SetLoadingImage(Image img)
    {
        LoadingImage = img;
    }

    public void SetBackgroundColour(Color col)
    {
        BackgroundColour = col;
    }

    public void SetOpacity(double Opa)
    {
        BackgroundOpacity = Opa;
    }

    private void AdjustPosition(object sender, EventArgs e)
    {
        //TopMost = true;
        BringToFront();

        ClientSize = MainControl.ClientSize;
        Location = MainControl.PointToScreen(Point.Empty);
        //Mainform.Activate();      
        //TopMost = false;
        BringToFront();
        Focus();
        //MakeTopMost(this);
    }
}

无论您调用 BringToFront() 多少次,它都不会将您的表单移动到活动表单之上。 BringToFront() 不会使控件成为顶级控件,也不会引发 Paint 事件。

修复它的方法太多了。 IMO 的最佳方法是让您的加载控件成为主窗体的子控件,而不是将它们分开,并且您必须在每次移动或调整大小后手动定位控件。

另一种方法是更改​​控件 window 的 z 顺序并在每次移动、调整大小或 maximize/minimize 事件引发后激活它。

这可以通过一些 p 调用来实现:

public void FocusForm()
{
    // force window to have focus
    uint foreThread = GetWindowThreadProcessId(GetForegroundWindow(), IntPtr.Zero);
    uint appThread = GetCurrentThreadId();
    const uint SW_SHOW = 5;
    if (foreThread != appThread)
    {
        AttachThreadInput(foreThread, appThread, true);
        BringWindowToTop(this.Handle);
        ShowWindow(this.Handle, SW_SHOW);
        AttachThreadInput(foreThread, appThread, false);
    }
    else
    {
        BringWindowToTop(this.Handle);
        ShowWindow(this.Handle, SW_SHOW);
    }
    this.Activate();
}

[DllImport("user32.dll")]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId);

[DllImport("kernel32.dll")]
static extern uint GetCurrentThreadId();

[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();

[DllImport("user32.dll")]
static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);

[DllImport("user32.dll", SetLastError = true)]
static extern bool BringWindowToTop(IntPtr hWnd);

[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, uint nCmdShow);

我用它来将我的主要 window 设置为最上面的,所以你可能想在最后失去 Activate() 调用。

我必须说,即使这可能对你有用[我还没有完全测试它的移动和调整大小],我建议你修改你的代码并把加载将窗体作为主窗体的子控件。

编辑:

如果需要透明控件可以勾选accepted answer to this SO question。我不能 post 这里的代码,因为我不想谎称这是我的代码。