表单覆盖显示移动和调整大小后面的表单

时间:2015-02-01 10:43:57

标签: c# winforms overlay bringtofront

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

当叠加显示它进入位置并且在调用它的主窗体的前面时,这看起来很棒。但是,当用户移动表单或调整表单大小时,表单将返回主表单。

当主窗体移动或调整大小时,叠加窗体会移动并调整大小,但是在完成调整大小或移动窗体后会移到主窗体后面。如何在不使用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);
    }
}

1 个答案:

答案 0 :(得分:1)

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

还有很多方法可以修复它。 IMO的最佳方法是使您的加载控件成为主窗体的子窗口而不是它们是分开的,您必须在每次移动或调整大小后手动定位控件。

可以做的另一种方法是更改​​控制窗口的z顺序,并在每次移动,调整大小或最大化/最小化事件后激活它。

这可以通过一些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);

我使用此功能将我的主窗口设置为最重要的,因此您可能希望最后丢失Activate()来电。

我必须说,即使这可能对您有用 [我还没有完全测试移动和调整大小] ,我建议您修改代码并将加载控件表格作为孩子到你的主要形式。

编辑:

如果您需要透明控件,则可以查看accepted answer to this SO question。我不能在这里发布代码,因为我不想虚假宣称它是我的代码。