Наложение формы, показываемое за формой при перемещении и изменении размера

Я настроил пользовательский элемент управления, который действует как наложение загрузки, наложение - это форма с картинкой для показа изображения.

Когда наложение показывает, что оно находится в позиции и находится перед основной формой, вызывающей его, это выглядит великолепно. Однако, когда пользователь перемещает форму или изменяет ее размер, форма возвращается к основной форме.

Наложенная форма перемещается и изменяет размеры без проблем, когда основная форма перемещается или изменяет размеры, однако после того, как она закончила изменять размер или перемещать форму, она выходит за основную форму. Как я могу вернуть оверлейную форму обратно наверх, не используя 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 ответ

Решение

Независимо от того, сколько раз вы звоните 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() позвоните в конце.

Я должен сказать, что даже если это может сработать для вас [я не полностью протестировал его на перемещение и изменение размера], я предлагаю вам пересмотреть свой код и поместить форму управления загрузкой в ​​качестве дочерней для вашей основной формы.

РЕДАКТИРОВАТЬ:

Если вам нужен прозрачный контроль, вы можете проверить принятый ответ на этот вопрос SO. Я не могу опубликовать код здесь, так как я не хочу ложно утверждать, что это мой код.

Другие вопросы по тегам