.NET消息框中的自定义按钮标题?

时间:2008-10-24 18:34:20

标签: .net vb.net winforms messagebox

是否有一种简单的方法可以在VB.NET中使用自定义按钮标题显示消息框?我在Stack Overflow存档中遇到了 What is an easy way to create a MessageBox with custom button text in Managed C++? ,但它是Managed C++

8 个答案:

答案 0 :(得分:18)

没有。
您必须使用FormBorderType = FixedDialog制作自定义表单。
这是一个小教程:

在.NET中创建对话框

作者:James D. Murray,2007年6月12日,70-526

Microsoft认证考试:70-526(MCTS)
目标:在Windows窗体应用程序中创建和使用自定义对话框 语言:Visual Basic 2005(单击此处查看此条目的C#版本)

我记得我第一次需要在.NET应用程序中创建一个用C#编写的对话框。作为一名长期的Visual Basic程序员,我认为这可以通过使用Visual Studio.NET附带的对话框模板轻松完成。令我惊讶的是,没有这样的表单模板存在于C#中,尽管有一个用于Visual Basic 2005.在浏览了几本充满Windows Forms 2.0编程信息的书籍和网页之后,我手动转换了一组基本步骤。 .NET表单进入Windows对话框:

步骤1:将表单添加到.NET项目并将其命名为“DialogBoxForm”。

步骤2:删除表单右下角区域的两个按钮,并将其命名为“OKButton”和“CancelButton”。

步骤3:更改表单的以下属性以将其外观和行为调整为标准对话框:

    Property        Value                   Description 
    -----------------------------------------------------------------------------------------------------------------------------
    AcceptButton    OK button instance      Causes form to return value DialogResult.OK. Only used on modal dialog boxes.
    CancelButton    Cancel button instance  Causes form to return value DialogResult.Cancel. Only used on modal dialog boxes.
    FormBorderStyle FixedDialog             Create a non-sizable form with no control box on the title bar.
    HelpButton      True    The Help button appears in the caption bar next to the Close button. The ControlBox property must be True for these buttons to be visible.
    MaximizeBox     False   Hide the Maximize button in the title bar.
    MinimizeBox     False   Hide the Minimize button in the title bar.
    ShowIcon        False   The title bar icon is not visible in a dialog box.
    ShowInTaskBar   False   Do not indicate the presence of the form on the Windows Task Bar.
    Start           Position    CenterParent    The initial position of a dialog box is over its parent form.
    Size            As Needed   The fixed size needed for the dialog box.

可以使用表单的“属性”窗口或使用表单的“加载”事件中的代码来设置这些属性:

    Me.AcceptButton = OKButton
    Me.CancelButton = CancelButton
    Me.FormBorderStyle = Windows.Forms.FormBorderStyle.FixedDialog
    Me.HelpButton = True
    Me.MaximizeBox = False
    Me.MinimizeBox = False
    Me.ShowInTaskbar = False
    Me.ShowIcon = False
    Me.StartPosition = FormStartPosition.CenterParent

步骤4:将以下按钮单击事件处理程序添加到表单:

    Private Sub OKButton_Click(ByVal sender As Object, _ByVal e As EventArgs)
        ' User clicked the OK button
        Me.DialogResult = Windows.Forms.DialogResult.OK
    End Sub

    Private Sub CancelButton_Click(ByVal sender As Object, _ByVal e As EventArgs)
        ' User clicked the Cancel button
        Me.DialogResult = Windows.Forms.DialogResult.Cancel
    End Sub

步骤5:添加将数据移入和移出对话框所需的属性,就像添加任何表单一样:

    Private _LoginName As String
    Private _LoginPassword As String

    Public Property LoginName() As String
        Get
            Return _LoginName
        End Get
        Set(ByVal value As String)
            _LoginName = value
        End Set
    End Property

    Public Property LoginPassword() As String
        Get
            Return _LoginPassword
        End Get
        Set(ByVal value As String)
            _LoginPassword = value
        End Set
    End Property

步骤6:通过调用表单的ShowDialog()以模态方式显示对话框:

    Public Sub ShowDialogBox()
        Dim dialog As New DialogBoxForm

        dialog.LoginName = "JDMurray"
        dialog.LoginPassword = String.Empty

        If dialog.ShowDialog() = Windows.Forms.DialogResult.OK Then
            Debug.WriteLine("Login Name: " & dialog.LoginName)
            Debug.WriteLine("Password: " & dialog.LoginPassword)
        Else
            ' User clicked the Cancel button
        End If
    End Sub

步骤7:要无模式显示对话框,请调用DialogBoxForm的Show()方法。您需要向DialogBoxForm的Close事件添加一个事件处理程序,以了解用户何时关闭对话框:

    Public Sub ShowDialogBox()
        Dim dialog As DialogBoxForm = New DialogBoxForm
        dialog.LoginName = "JDMurray"
        dialog.Password = String.Empty
        AddHandler dialog.FormClosed, AddressOf dialog_FormClosed
        dialog.Show()

        ' The Show() method returns immediately
    End Sub

    Private Sub dialog_FormClosed(ByVal sender As Object, _

     ByVal e As FormClosedEventArgs)
        ' This method is called when the user closes the dialog box
    End Sub

答案 1 :(得分:16)

MessageBox使用一个可以像任何其他窗口一样混淆的普通窗口。 Windows已经有很长一段时间了,已经有20多年了。这些技术越来越模糊,太多的友好类包装器隐藏了原生的winapi并且没有公开你可以用它做的一切。所以程序员现在自动认为这是不可能的,正如你可以从upvoted答案中看出来的那样。这是Petzold在其开创性的“编程Windows”一书中教给我们的一种编程。用自定义窗体或窗口替换MessageBox实际上很难做到,它可以实现非平凡的自动布局以适应文本并支持本地化而无需帮助。虽然这正是你似乎不喜欢的东西:)

Anyhoo,消息框窗口很容易找回。它由UI线程拥有,并具有一个特殊的类名,使其独一无二。 EnumThreadWindows()枚举一个线程拥有的窗口,GetClassName()允许您检查窗口的类型。然后使用SetWindowText()将文本戳到按钮中。

在项目中添加一个新类并粘贴下面显示的代码。使用以下代码调用它:

Nobugz.PatchMsgBox(New String() {"Da", "Njet"})
MsgBox("gack", MsgBoxStyle.YesNo)

以下是代码:

Imports System.Text
Imports System.Runtime.InteropServices

Public Class Nobugz
  Private Shared mLabels() As String    '' Desired new labels
  Private Shared mLabelIndex As Integer '' Next caption to update

  Public Shared Sub PatchMsgBox(ByVal labels() As String)
    ''--- Updates message box buttons
    mLabels = labels
    Application.OpenForms(0).BeginInvoke(New FindWindowDelegate(AddressOf FindMsgBox), GetCurrentThreadId())
  End Sub

  Private Shared Sub FindMsgBox(ByVal tid As Integer)
    ''--- Enumerate the windows owned by the UI thread
    EnumThreadWindows(tid, AddressOf EnumWindow, IntPtr.Zero)
  End Sub

  Private Shared Function EnumWindow(ByVal hWnd As IntPtr, ByVal lp As IntPtr) As Boolean
    ''--- Is this the message box?
    Dim sb As New StringBuilder(256)
    GetClassName(hWnd, sb, sb.Capacity)
    If sb.ToString() <> "#32770" Then Return True
    ''--- Got it, now find the buttons
    mLabelIndex = 0
    EnumChildWindows(hWnd, AddressOf FindButtons, IntPtr.Zero)
    Return False
  End Function

  Private Shared Function FindButtons(ByVal hWnd As IntPtr, ByVal lp As IntPtr) As Boolean
    Dim sb As New StringBuilder(256)
    GetClassName(hWnd, sb, sb.Capacity)
    If sb.ToString() = "Button" And mLabelIndex <= UBound(mLabels) Then
      ''--- Got one, update text
      SetWindowText(hWnd, mLabels(mLabelIndex))
      mLabelIndex += 1
    End If
    Return True
  End Function

  ''--- P/Invoke declarations
  Private Delegate Sub FindWindowDelegate(ByVal tid As Integer)
  Private Delegate Function EnumWindowDelegate(ByVal hWnd As IntPtr, ByVal lp As IntPtr) As Boolean
  Private Declare Auto Function EnumThreadWindows Lib "user32.dll" (ByVal tid As Integer, ByVal callback As EnumWindowDelegate, ByVal lp As IntPtr) As Boolean
  Private Declare Auto Function EnumChildWindows Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal callback As EnumWindowDelegate, ByVal lp As IntPtr) As Boolean
  Private Declare Auto Function GetClassName Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal name As StringBuilder, ByVal maxlen As Integer) As Integer
  Private Declare Auto Function GetCurrentThreadId Lib "kernel32.dll" () As Integer
  Private Declare Auto Function SetWindowText Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal text As String) As Boolean
End Class

答案 2 :(得分:8)

没有方法可以访问或重定向Messagebox的默认按钮文本。

执行此操作的唯一方法是编写自己的代码,或者只使用互联网中的许多免费代码之一:

Free MsgBoxGo!

答案 3 :(得分:2)

有一个解决方案。通过安装CBT挂钩,可以动态调整各种MessageBox视觉设置:消息和按钮字体,对话框背景,对话框定位,图标,按钮标题,超时,甚至插入其他控件。

完整的解决方案:扩展的MessageBox .NET程序集 http://www.news2news.com/vfp/?solution=5

这是一个功能齐全的试用版,常规版包含完整的C#源代码。

答案 4 :(得分:1)

完成同样事情的C#代码可以在MSDN论坛https://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=3087899&SiteID=1下的文章中找到。

答案 5 :(得分:1)

将此添加到您希望显示对话框的按钮。 这是一个自定义形式的messageBox;

    private void DGroup_Click(object sender, EventArgs e)
    {
        messageBox m = new messageBox();
        m.ShowDialog();
        if (m.DialogResult == DialogResult.Yes)
        {
            //del(groups.php?opt=del&amp;id=613','asdasd');
            String[] asd = new String[2];
            asd[0] = "groups.php?opt=del&amp;id=613";
            asd[1] = "asdasd";
            addgroup.Document.InvokeScript("del",asd);
        }
        else
            if (m.DialogResult == DialogResult.No)
            {
                MessageBox.Show("App won´t close");
            }
    }

将此代码添加到messageBox。

    private void deleteGroupOnly_Click(object sender, EventArgs e)
    {
        this.DialogResult = DialogResult.Yes;
        this.Close();
    }

    private void deleteAll_Click(object sender, EventArgs e)
    {
        this.DialogResult = DialogResult.No;
        this.Close();
    }

    private void cancel_Click(object sender, EventArgs e)
    {
        this.DialogResult = DialogResult.Cancel;
        this.Close();
    }

答案 6 :(得分:1)

Daniel Nolan的解决方案,VB.Net中的代码

positionType="FixRelativeToTop"

答案 7 :(得分:0)

这是一个C#片段,它使用Win32钩子来改变按钮标题(来自http://icodesnip.com/snippet/csharp/custom-messagebox-buttons):

        [DllImport("kernel32.dll")]
        static extern uint GetCurrentThreadId();

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        private static extern int CallNextHookEx(int idHook, int nCode, IntPtr wParam, IntPtr lParam);

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        private static extern bool UnhookWindowsHookEx(int idHook);

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        private static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);

        [DllImport("user32.dll")]
        private static extern bool SetDlgItemText(IntPtr hWnd, int nIDDlgItem, string lpString);

        delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam);

        static HookProc dlgHookProc;

        private const long WH_CBT = 5;
        private const long HCBT_ACTIVATE = 5;

        private const int ID_BUT_OK = 1;
        private const int ID_BUT_CANCEL = 2;
        private const int ID_BUT_ABORT = 3;
        private const int ID_BUT_RETRY = 4;
        private const int ID_BUT_IGNORE = 5;
        private const int ID_BUT_YES = 6;
        private const int ID_BUT_NO = 7;

        private const string BUT_OK = "Save";
        private const string BUT_CANCEL = "Cancel";
        private const string BUT_ABORT = "Stop";
        private const string BUT_RETRY = "Continue";
        private const string BUT_IGNORE = "Ignore";
        private const string BUT_YES = "Yeeh";
        private const string BUT_NO = "Never";

        private static int _hook = 0;

        private static int DialogHookProc(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode < 0)
            {
                return CallNextHookEx(_hook, nCode, wParam, lParam);
            }

            if (nCode == HCBT_ACTIVATE)
            {
                SetDlgItemText(wParam, ID_BUT_OK, BUT_OK);
                SetDlgItemText(wParam, ID_BUT_CANCEL, BUT_CANCEL);
                SetDlgItemText(wParam, ID_BUT_ABORT, BUT_ABORT);
                SetDlgItemText(wParam, ID_BUT_RETRY, BUT_RETRY);
                SetDlgItemText(wParam, ID_BUT_IGNORE, BUT_IGNORE);
                SetDlgItemText(wParam, ID_BUT_YES, BUT_YES);
                SetDlgItemText(wParam, ID_BUT_NO, BUT_NO);
            }

            return CallNextHookEx(_hook, nCode, wParam, lParam);
        }

        private void Button_Click(object sender, EventArgs e)
        {
            dlgHookProc = new HookProc(DialogHookProc);

            _hook = SetWindowsHookEx((int)WH_CBT, dlgHookProc, (IntPtr)0, (int)GetCurrentThreadId());

            DialogResult dlgEmptyCheck = MessageBox.Show("Text", "Caption", MessageBoxButtons.AbortRetryIgnore, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button3);

            if (dlgEmptyCheck == DialogResult.Abort)
            {

            }

            UnhookWindowsHookEx(_hook);
        }