Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom button captions in .NET messagebox?

Is there an easy way to display a messagebox in VB.NET with custom button captions? I came across What is an easy way to create a MessageBox with custom button text in Managed C++?, in the Stack Overflow archives, but it's for Managed C++.

like image 484
subrama6 Avatar asked Oct 24 '08 18:10

subrama6


People also ask

What is the difference between MsgBox and MessageBox show?

MsgBox() is the same as Messagebox. Show() . It exists for VB6 programmers who are used to it. There are no rules on which one to use, but since MsgBox simply ends up delegating to MessageBox , I personally would go directly with MessageBox .

What is MessageBox class explain MessageBox () in detail?

A message box is a prefabricated modal dialog box that displays a text message to a user. You show a message box by calling the static Show method of the MessageBox class. The text message that is displayed is the string argument that you pass to Show.

Which is the default MessageBox button?

The first button on the message box is the default button.


2 Answers

MessageBox uses a plain window that can be messed with like any other window. This has been possible in Windows for a very long time, well over 20 years already. The techniques are getting obscure though, too many friendly class wrappers that hide the native winapi and don't expose everything you can do with it. So much so that programmers now automatically assume that this isn't possible, as you can tell from the upvoted answers. It is the kind of programming that Petzold taught us in his seminal "Programming Windows" book. Replacing MessageBox with a custom Form or Window is actually fairly hard to do, it does non-trivial automatic layout to fit the text and supports localization without help. Although that's exactly what you don't seem to like :)

Anyhoo, the message box window is easy to find back. It is owned by the UI thread and has a special class name that makes it unique. EnumThreadWindows() enumerates the windows owned by a thread, GetClassName() lets you check the kind of window. Then just poke the text into the button with SetWindowText().

Add a new class to your project and paste the code shown below. Invoke it with code like this:

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

Here's the code:

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
like image 133
Hans Passant Avatar answered Oct 17 '22 08:10

Hans Passant


No.
You'll have to make a custom form with FormBorderType = FixedDialog.
Here is a little tutorial:

Creating Dialog Boxes in .NET

by James D. Murray on Jun.12, 2007, under 70-526

Microsoft Certification Exam: 70-526 (MCTS)
Objective: Create and use custom dialog boxes in Windows Forms applications.
Language: Visual Basic 2005 (click here for the C# version of this entry)

I remember the first time I needed to create a dialog box in a .NET application that I was writing in C#. Being a long-time Visual Basic programmer, I assumed that this could easily be accomplished by using a dialog box template included with Visual Studio.NET. To my surprise, no such form template existed for C#, although one does for Visual Basic 2005. After wading through several books and Web pages filled with information on Windows Forms 2.0 programming, a basic set of steps became apparent to me for manually converting a .NET form into a Windows dialog box:

Step 1 : Add a Form to your .NET project and name it “DialogBoxForm”.

Step 2 : Drop two buttons in the lower right-hand area of the Form and name them “OKButton” and “CancelButton”.

Step 3 : Change the following properties of the Form to adjust its appearance and behavior to be like a standard dialog box:

    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.

These properties can be set using the Properties window for the form, or using code placed in the Form’s Load event:

    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

Step 4 : Add the following button click event handlers to the Form:

    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

Step 5 : Add properties that you need to move data into and out of the dialog box as you would for any Form:

    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

Step 6 : Show the dialog box modally by calling the ShowDialog() of the form:

    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

Step 7 : To show the dialog box modelessly, call the Show() method of DialogBoxForm instead. You will need to add an event handler to the Close event of DialogBoxForm to know when the user closes the dialog box:

    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
like image 19
BradC Avatar answered Oct 17 '22 08:10

BradC