Winforms-Как я могу создать MessageBox в центре MainForm?

Winforms-Как я могу сделать диалоговые окна в центре MainForm? Это в отличие от того, чтобы основываться на стандартном стандартном окне Windows, которое отображает их в центре экрана.

В моем случае у меня есть небольшая основная форма, которая может быть, например, расположена в углу, всплывающее окно MessageBox отображается, что кажется пустым.

Ответ 1

Это возможно с некоторыми порциями P/Invoke и магией, предоставляемыми Control.BeginInvoke(). Добавьте новый класс в проект и вставьте этот код:

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

class CenterWinDialog : IDisposable {
    private int mTries = 0;
    private Form mOwner;

    public CenterWinDialog(Form owner) {
        mOwner = owner;
        owner.BeginInvoke(new MethodInvoker(findDialog));
    }

    private void findDialog() {
        // Enumerate windows to find the message box
        if (mTries < 0) return;
        EnumThreadWndProc callback = new EnumThreadWndProc(checkWindow);
        if (EnumThreadWindows(GetCurrentThreadId(), callback, IntPtr.Zero)) {
            if (++mTries < 10) mOwner.BeginInvoke(new MethodInvoker(findDialog));
        }
    }
    private bool checkWindow(IntPtr hWnd, IntPtr lp) {
        // Checks if <hWnd> is a dialog
        StringBuilder sb = new StringBuilder(260);
        GetClassName(hWnd, sb, sb.Capacity);
        if (sb.ToString() != "#32770") return true;
        // Got it
        Rectangle frmRect = new Rectangle(mOwner.Location, mOwner.Size);
        RECT dlgRect;
        GetWindowRect(hWnd, out dlgRect);
        MoveWindow(hWnd,
            frmRect.Left + (frmRect.Width - dlgRect.Right + dlgRect.Left) / 2,
            frmRect.Top + (frmRect.Height - dlgRect.Bottom + dlgRect.Top) / 2,
            dlgRect.Right - dlgRect.Left,
            dlgRect.Bottom - dlgRect.Top, true);
        return false;
    }
    public void Dispose() {
        mTries = -1;
    }

    // P/Invoke declarations
    private delegate bool EnumThreadWndProc(IntPtr hWnd, IntPtr lp);
    [DllImport("user32.dll")]
    private static extern bool EnumThreadWindows(int tid, EnumThreadWndProc callback, IntPtr lp);
    [DllImport("kernel32.dll")]
    private static extern int GetCurrentThreadId();
    [DllImport("user32.dll")]
    private static extern int GetClassName(IntPtr hWnd, StringBuilder buffer, int buflen);
    [DllImport("user32.dll")]
    private static extern bool GetWindowRect(IntPtr hWnd, out RECT rc);
    [DllImport("user32.dll")]
    private static extern bool MoveWindow(IntPtr hWnd, int x, int y, int w, int h, bool repaint);
    private struct RECT { public int Left; public int Top; public int Right; public int Bottom; }
}

Использование образца:

    private void button1_Click(object sender, EventArgs e) {
        using (new CenterWinDialog(this)) {
            MessageBox.Show("Nobugz waz here");
        }
    }

Обратите внимание, что этот код работает для любого из диалогов Windows. MessageBox, OpenFormDialog, FolderBrowserDialog, PrintDialog, ColorDialog, FontDialog, PageSetupDialog, SaveFileDialog.

Ответ 2

Это для Win32 API, написанное на C. Перевести его как вам нужно...

case WM_NOTIFY:{
  HWND X=FindWindow("#32770",NULL);
  if(GetParent(X)==H_frame){int Px,Py,Sx,Sy; RECT R1,R2;
    GetWindowRect(hwnd,&R1); GetWindowRect(X,&R2);
    Sx=R2.right-R2.left,Px=R1.left+(R1.right-R1.left)/2-Sx/2;
    Sy=R2.bottom-R2.top,Py=R1.top+(R1.bottom-R1.top)/2-Sy/2;
    MoveWindow(X,Px,Py,Sx,Sy,1);
  }
} break;

Добавьте это в код WndProc... Вы можете установить позицию по своему усмотрению, в этом случае она просто центрируется по основному окну программы. Он будет делать это для любого окна сообщений или диалога открытия/сохранения файлов и, возможно, некоторых других встроенных элементов управления. Я не уверен, но я думаю, вам может понадобиться включить COMMCTRL или COMMDLG, чтобы использовать это, по крайней мере, если вы хотите открыть/сохранить диалоги.

Я экспериментировал с просмотром кодов уведомлений и hwndFrom от NMHDR, а затем решил, что это было так же эффективно и намного проще, а не. Если вы действительно хотите быть очень конкретным, скажите FindWindow, чтобы найти уникальную подпись (заголовок), которую вы указываете в окне, которое вы хотите найти.

Это срабатывает, прежде чем окно сообщения будет выведено на экран, поэтому, если вы установите глобальный флаг, чтобы указать, когда действие выполняется вашим кодом, и найдите уникальный заголовок, вы убедитесь, что действия, которые вы предпринимаете, будут возникать только один раз (будет вероятно, будут несколько уведомлений). Я не изучил это подробно, но мне удалось получить CreateWindow, чтобы поместить окно редактирования в диалоговом окне с сообщениями. Это выглядело неуместным, как уши крысы, привитые к позвоночнику клонированной свиньи, но это работает. Делать вещи таким образом может быть намного проще, чем иметь возможность сворачивать свои собственные.

Crow.

EDIT: небольшая коррекция, чтобы убедиться, что обработано правое окно. Убедитесь, что родительские ручки согласованы во всем, и это должно работать нормально. Это для меня, даже с двумя экземплярами одной и той же программы...

Ответ 3

Напишите свой собственный почтовый ящик. Форма и ярлык должны это сделать. Или вам также нужно глобализовать его?

Ответ 4

Класс оказался применимым к двум другим ситуациям. У меня был FolderBrowserDialog, который я хотел бы увеличить, и я хотел, чтобы он приблизился к левому верхнему углу родительского диалога (рядом с кнопкой, которую я нажимаю, чтобы открыть ее).

Я скопировал класс CenterWinDialog и сделал два новых класса. Один класс изменяет размер диалогового окна, а другой изменяет свою позицию на определенное смещение от родительской формы. Это использование:

        using (new OffsetWinDialog(this) { PreferredOffset = new Point(75, 75 )})
        using (new SizeWinDialog(this)   { PreferredSize   = new Size(400, 600)})
        {
            DialogResult result = dlgFolderBrowser.ShowDialog();
            if (result == DialogResult.Cancel)
                return;
        }

и это два класса, основанные на исходном.

class OffsetWinDialog : IDisposable
{
    private int mTries = 0;
    private Form mOwner;

    public OffsetWinDialog(Form owner)
    {
        mOwner = owner;
        owner.BeginInvoke(new MethodInvoker(findDialog));
    }

    public Point PreferredOffset { get; set; }

    private void findDialog()
    {
        // Enumerate windows to find the message box
        if (mTries < 0) 
            return;
        EnumThreadWndProc callback = new EnumThreadWndProc(checkWindow);
        if (EnumThreadWindows(GetCurrentThreadId(), callback, IntPtr.Zero))
        {
            if (++mTries < 10)
                mOwner.BeginInvoke(new MethodInvoker(findDialog));
        }
    }
    private bool checkWindow(IntPtr hWnd, IntPtr lp)
    {
        // Checks if <hWnd> is a dialog
        StringBuilder sb = new StringBuilder(260);
        GetClassName(hWnd, sb, sb.Capacity);
        if (sb.ToString() != "#32770") return true;
        // Got it
        Rectangle frmRect = new Rectangle(mOwner.Location, mOwner.Size);
        RECT dlgRect;
        GetWindowRect(hWnd, out dlgRect);
        MoveWindow(hWnd,
            frmRect.Left   + PreferredOffset.X,
            frmRect.Top    + PreferredOffset.Y,
            dlgRect.Right  - dlgRect.Left,
            dlgRect.Bottom - dlgRect.Top, 
            true);
        return false;
    }
    public void Dispose()
    {
        mTries = -1;
    }

    // P/Invoke declarations
    private delegate bool EnumThreadWndProc(IntPtr hWnd, IntPtr lp);
    [DllImport("user32.dll")]
    private static extern bool EnumThreadWindows(int tid, EnumThreadWndProc callback, IntPtr lp);
    [DllImport("kernel32.dll")]
    private static extern int GetCurrentThreadId();
    [DllImport("user32.dll")]
    private static extern int GetClassName(IntPtr hWnd, StringBuilder buffer, int buflen);
    [DllImport("user32.dll")]
    private static extern bool GetWindowRect(IntPtr hWnd, out RECT rc);
    [DllImport("user32.dll")]
    private static extern bool MoveWindow(IntPtr hWnd, int x, int y, int w, int h, bool repaint);
    private struct RECT { public int Left; public int Top; public int Right; public int Bottom; }
}

и

class SizeWinDialog : IDisposable
{
    private int mTries = 0;
    private Form mOwner;

    public SizeWinDialog(Form owner)
    {
        mOwner = owner;
        mOwner.BeginInvoke(new Action(findDialog));
    }

    public Size PreferredSize { get; set; }

    private void findDialog()
    {
        // Enumerate windows to find the message box
        if (mTries < 0) 
            return;
        EnumThreadWndProc callback = new EnumThreadWndProc(checkWindow);
        if (EnumThreadWindows(GetCurrentThreadId(), callback, IntPtr.Zero))
        {
            if (++mTries < 10) 
                mOwner.BeginInvoke(new MethodInvoker(findDialog));
        }
    }
    private bool checkWindow(IntPtr hWnd, IntPtr lp)
    {
        // Checks if <hWnd> is a dialog
        StringBuilder sb = new StringBuilder(260);
        GetClassName(hWnd, sb, sb.Capacity);
        if (sb.ToString() != "#32770") 
            return true;
        // Got it
        Rectangle frmRect = new Rectangle(mOwner.Location, mOwner.Size);
        RECT dlgRect;
        GetWindowRect(hWnd, out dlgRect);
        SetWindowPos(new HandleRef(this, hWnd), new HandleRef(), dlgRect.Left, dlgRect.Top, PreferredSize.Width, PreferredSize.Height, 20 | 2);
        return false;
    }
    public void Dispose()
    {
        mTries = -1;
    }

    // P/Invoke declarations
    private delegate bool EnumThreadWndProc(IntPtr hWnd, IntPtr lp);
    [DllImport("user32.dll")]
    private static extern bool EnumThreadWindows(int tid, EnumThreadWndProc callback, IntPtr lp);
    [DllImport("kernel32.dll")]
    private static extern int GetCurrentThreadId();
    [DllImport("user32.dll")]
    private static extern int GetClassName(IntPtr hWnd, StringBuilder buffer, int buflen);
    [DllImport("user32.dll")]
    private static extern bool GetWindowRect(IntPtr hWnd, out RECT rc);
    [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
    public static extern bool SetWindowPos(HandleRef hWnd, HandleRef hWndInsertAfter, int x, int y, int cx, int cy,
        int flags);

    private struct RECT { public int Left; public int Top; public int Right; public int Bottom; }
}

Ответ 5

Создайте свой собственный..

 public partial class __MessageBox : Form
   {
      public MMMessageBox(string title, string message)
      {
         InitializeComponent();
         this.Text = title;
         this.labelString.Text = message;
      }
   }