web-dev-qa-db-fra.com

WinForms-Comment puis-je faire apparaître MessageBox centré sur Mainform?

WinForms-Comment puis-je faire apparaître des boîtes de dialogue centrées sur Mainform? À ce sujet, par opposition à être basée sur une défaillance de Windows normale qui les rend dans le centre de l'écran.

Dans mon cas, j'ai une petite forme principale qui peut par exemple être positionnée dans un coin, la popup MessageBox est affichée ce qui semble une façade.

50
Greg

Il est possible de certaines portions de p/invoke et de la magie fournie par Control.begininvoke (). Ajoutez une nouvelle classe à votre projet et collez ce code:

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; }
}

Utilisation des échantillons:

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

Notez que ce code fonctionne pour l'une des boîtes de dialogue Windows. MessageBox, OpenFormDialog, FolderbrowseerDialog, PrintDialog, Colordialog, FontDialog, PagesTupDialog, SaviterfileDialog.

64
Hans Passant

Ceci est pour Win32 API, écrit en C. Traduisez-le comme vous avez besoin ...

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;

Ajoutez-le au code WNDProc ... Vous pouvez définir la position comme vous le souhaitez, dans ce cas, il est centré sur la fenêtre du programme principal. Cela fera cela pour toute MessageBox ou Fichier Ouvrir/Enregistrer la boîte de dialogue et probablement d'autres contrôles natifs. Je ne suis pas sûr, mais je pense que vous devrez peut-être inclure COMMCTRL ou COMMDLG pour l'utiliser, au moins, vous le souhaitez si vous souhaitez ouvrir/enregistrer des boîtes de dialogue.

J'ai expérimenté avec la recherche des codes de notify et de la HWNDFROM du NMHDR, puis a décidé que c'était tout aussi efficace, et bien plus facile, et non. Si vous voulez vraiment être très précis, dites à Findwindow de rechercher une légende unique (titre) que vous donnez à la fenêtre que vous souhaitez trouver.

Ce déclenche avant que la messagerie est dessinée à l'écran, donc si vous définissez un drapeau global pour indiquer lorsque vous avez effectué votre code et recherchez une légende unique, vous êtes sûr que les actions que vous prenez ne se produiront qu'une fois (il y aura probablement plusieurs notifiants). Je n'ai pas exploré cela en détail, mais j'ai réussi à créer Creewindow de mettre une boîte d'édition sur une boîte de dialogue MessageBox/il avait l'air d'une oreille de rat greffée sur la colonne vertébrale d'un cochon cloné, mais cela fonctionne. Faire des choses de cette façon peut être beaucoup plus facile que de devoir rouler le vôtre.

Corbeau.

EDIT: Petite correction pour vous assurer que la bonne fenêtre est manipulée. Assurez-vous que les membres du parent conviennent tout au long, et cela devrait fonctionner correctement. C'est pour moi, même avec deux instances du même programme ...

2
user1418124

La classe s'est révélée être applicable à deux autres situations. J'ai eu un folderbrowseerdialog que je voulais être plus grand, et je voulais qu'il vienne près du haut à gauche de la boîte de dialogue Parent (près du bouton, je clique pour l'ouvrir).

J'ai copié la classe CenterWinDindialog et j'ai fabriqué deux nouvelles classes. Une classe change la taille de la boîte de dialogue et l'autre modifie sa position à un décalage spécifique à partir du formulaire parent. C'est l'utilisation:

        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;
        }

et ce sont les deux classes basées sur l'original.

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; }
}

et

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
RonSanderson

Écrivez votre propre message boîte. Un formulaire et une étiquette devraient le faire. Ou avez-vous également besoin de le mondialiser?

1
Pedery

Crée le tien..

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