0

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

当覆盖显示它进入位置并位于调用它的主窗体的前面时,这看起来很棒。但是,当用户移动表单或调整其大小时,表单会转到主表单。

当主窗体正在移动或调整大小时,覆盖窗体可以毫无问题地移动和调整大小,但是在完成调整大小或移动后,窗体会移到主窗体后面。如何在不使用 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);
    }
}
4

1 回答 1

1

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

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

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

这可以通过一些 p-invokes 来实现:

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()在最后失去呼叫。

我必须说,即使这可能对你有用[我还没有完全测试它的移动和调整大小],我建议你修改你的代码并将加载控制表单作为一个子表单放到你的主表单中。

编辑:

如果您需要透明控制,则可以检查此 SO question 的已接受答案。我不能在这里发布代码,因为我不想错误地声称它是我的代码。

于 2015-02-01T11:06:37.730 回答