Winforms-Как я могу сделать так, чтобы MessageBox отображался в центре MainForm? - PullRequest
47 голосов
/ 05 апреля 2010

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

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

Ответы [ 5 ]

58 голосов
/ 05 апреля 2010

Это возможно с некоторыми порциями 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 голосов
/ 25 мая 2012

Это для 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НМГДР, то решил, что это так же эффективно, и гораздо проще, а не так.Если вы действительно хотите быть очень конкретным, попросите FindWindow найти уникальный заголовок (заголовок), который вы даете окну, которое вы хотите найти.

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

Ворона.

РЕДАКТИРОВАТЬ: Небольшая поправка, чтобы убедиться, что правое окно обрабатывается.Убедитесь, что родительские дескрипторы согласуются во всем, и это должно работать нормально.Это для меня, даже с двумя экземплярами одной и той же программы ...

1 голос
/ 23 декабря 2016

Класс оказался применимым к двум другим ситуациям. У меня был 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; }
}
1 голос
/ 05 апреля 2010

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

0 голосов
/ 02 мая 2019

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

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