Reputation: 465
I want to ask user for example "Do you want to go right or left?".
To have simple Code I use MSGBOX with a prompt like:
"Do you want to go right or left"
Press "YES for 'right' / NO for 'left'"
Then I process Yes/No/Cancel that was pressed. This works but is ugly and in some cases hard to understand.
Also in Addition in some cases I have more than 2 choices - but that is probable another question...
Upvotes: 3
Views: 35665
Reputation: 331
I've created my own custom class that recreates a dialog with a form created from code, rather than building it through visual studio's UI. you can create a new class in your project, call it "Msg", and use the code below:
the function within the class is
Show("string, or RTFEncodedString", optional Buttons, optional Icon, optional Title, optional Width, optional Height, optional DurationMs, optional BackColour, optional pictureBox)
so at minimum, you'd have:
Msg.Show("hello world")
very similar to msgbox("hello world") or message.show("hello world") and, MsgBox() is more limited than message.show - because the latter can have icons, but thats about it. whereas my class Msg.Show() can have all kinds like this:
for a 600 x 300 dialog, with yes no cancel buttons, and information icon, and will show for 5000 milliseconds
Msg.Show("hello world", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Information, "Title text", 600, 300, 5000)
the same, but to show indefinately just set duration to 0
Msg.Show("hello world", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Information, "Title text", 600, 300, 0)
want to change the back colour as well?
Msg.Show("hello world", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Information, "Title text", 600, 300, 5000, color.lightBlue)
want to add a graphic? screenshot / image?
Msg.Show("hello world", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Information, "Title text", 600, 300, 5000, color.lightBlue, examplePicturebox)
it accepts richtext in RTF format too, so you can have bold, underline, italics, colours, highlighted text, change font-family, or font size, etc.
heres the code - written in .NET 4.0:
Imports System.Windows.Forms
Imports System.Drawing
Public Class msg
Private Shared _result As DialogResult
Private Shared _formWidth As Integer = 400
Private Shared _formHeight As Integer = 250
Private Shared _timer As Timer
Private Shared _duration As Integer
Private Shared isTimerRunning As Boolean = False
Private Shared useDynamicHeight As Boolean = False
Public Shared minimumDialogWidth As Integer = 400
Public Shared minimumDialogHeight As Integer = 180
Public Shared maximumDialogWidth As Integer = 1500
Public Shared maximumDialogHeight As Integer = 1000
Public Shared selectedBackColour As Color = SystemColors.Control
Public Shared ReplaceThisWithYourOwnImage As New PictureBox
Public Shared Function Show(message As String, Optional buttons As MessageBoxButtons = MessageBoxButtons.OK, Optional icon As MessageBoxIcon = MessageBoxIcon.None, Optional title As String = "", Optional dialogWidth As Integer = 400, Optional dialogHeight As Integer = 250, Optional durationMilliseconds As Integer = 0, Optional backColor As Color? = Nothing, Optional ByVal graphics As PictureBox = Nothing) As DialogResult
_result = DialogResult.None ' Reset _result
Dim _form As New Form()
Dim actualBackColor As Color = If(backColor.HasValue, backColor.Value, SystemColors.Control)
Dim _rtbTitle As New RichTextBox()
Dim _rtbMessage As New RichTextBox()
Dim _btnYes As New Button()
Dim _btnNo As New Button()
Dim _btnCancel As New Button()
Dim _btnOK As New Button()
Dim _title As String = title
Dim _message As String = message
Dim _buttons As MessageBoxButtons = buttons
Dim _icon As MessageBoxIcon = icon
Try
' check for minimum & maximum values
If dialogWidth < minimumDialogWidth Then
dialogWidth = minimumDialogWidth
End If
If dialogHeight < minimumDialogHeight Then
dialogHeight = minimumDialogHeight
End If
If dialogWidth > maximumDialogWidth Then
dialogWidth = maximumDialogWidth
End If
If dialogHeight > maximumDialogHeight Then
dialogHeight = maximumDialogHeight
End If
Catch ex As Exception
' SUPRESS
End Try
Dim _formWidth As Integer = dialogWidth
Dim _formHeight As Integer = dialogHeight
Dim _duration As Integer = durationMilliseconds
' If Duration has been set, meaning timer will be enabled, set the flag to TRUE
If _duration > 0 Then
isTimerRunning = True
End If
' Initialize the Form and its Controls
InitializeForm(_form, _rtbTitle, _rtbMessage, _btnYes, _btnNo, _btnCancel, _btnOK, _title, _message, _buttons, _icon, _formWidth, _formHeight, _duration, actualBackColor, graphics)
Try
' Show the Form
_form.ShowDialog()
Catch ex As Exception
' SUPRESS
End Try
Return _result
End Function
Private Shared Sub InitializeForm(ByRef _form As Form, ByRef _rtbTitle As RichTextBox, ByRef _rtbMessage As RichTextBox, ByRef _btnYes As Button, ByRef _btnNo As Button, ByRef _btnCancel As Button, ByRef _btnOK As Button, title As String, message As String, buttons As MessageBoxButtons, icon As MessageBoxIcon, dialogWidth As Integer, dialogHeight As Integer, duration As Integer, backColor As Color, Optional ByVal pictureBox As PictureBox = Nothing)
_form = New Form()
_form.FormBorderStyle = FormBorderStyle.FixedDialog
_form.StartPosition = FormStartPosition.CenterScreen
_form.Width = dialogWidth
_form.Height = dialogHeight
_form.BackColor = backColor
_form.MinimizeBox = False
_form.MaximizeBox = False
_form.Text = title
_form.TopMost = True
' Icon Parameters
Dim iconPictureBox As New PictureBox()
iconPictureBox.SizeMode = PictureBoxSizeMode.StretchImage
iconPictureBox.Width = 32
iconPictureBox.Height = 32
iconPictureBox.Location = New Point(10, 10)
Select Case icon
Case MessageBoxIcon.Information
iconPictureBox.Image = SystemIcons.Information.ToBitmap()
_rtbTitle.ForeColor = Color.Black
Case MessageBoxIcon.Warning Or MessageBoxIcon.Exclamation
iconPictureBox.Image = SystemIcons.Warning.ToBitmap()
_rtbTitle.ForeColor = Color.Black
Case MessageBoxIcon.Error Or MessageBoxIcon.Hand
iconPictureBox.Image = SystemIcons.Error.ToBitmap()
_rtbTitle.ForeColor = Color.Red
Case MessageBoxIcon.Question
iconPictureBox.Image = SystemIcons.Question.ToBitmap()
_rtbTitle.ForeColor = Color.Black
Case Else
' No icon
_rtbTitle.ForeColor = Color.Black
iconPictureBox.Width = 0
End Select
' Add Icon To the Form
_form.Controls.Add(iconPictureBox)
Dim rtbPadding As Integer = 35
Dim buttonPadding As Integer = 10
Dim buttonHeight As Integer = 25
' RichTextBox Parameters
_rtbTitle.Text = title
_rtbTitle.Font = New Font("Calibri", 14, FontStyle.Regular)
_rtbTitle.ReadOnly = True
_rtbTitle.Enabled = True
_rtbTitle.BackColor = _form.BackColor
_rtbTitle.BorderStyle = BorderStyle.None
_rtbTitle.Width = _form.Width - iconPictureBox.Width - rtbPadding - buttonPadding
_rtbTitle.Height = 30
If iconPictureBox.Width > 0 Then
_rtbTitle.Location = New Point(iconPictureBox.Width + 20, 15) ' Set the location
Else
_rtbTitle.Location = New Point(10, 15) ' Set the location
End If
' Add the RichTextBox To the Form
_form.Controls.Add(_rtbTitle)
_rtbMessage.Rtf = ConvertPlainTextToRTF(message)
'_rtbMessage.Font = New Font("Calibri", 10.5, FontStyle.Regular)
_rtbMessage.ReadOnly = True
_rtbMessage.Enabled = True
_rtbMessage.BackColor = _form.BackColor
_rtbMessage.WordWrap = True
_rtbMessage.BorderStyle = BorderStyle.None
_rtbMessage.Width = _form.Width - rtbPadding
' Calculate Height based on message length
Dim lineHeight As Integer = TextRenderer.MeasureText("Text", _rtbMessage.Font).Height
Dim lines As Integer = _rtbMessage.GetLineFromCharIndex(_rtbMessage.TextLength) + 1
Dim requiredHeight As Integer = lineHeight * lines + lineHeight
_rtbMessage.Height = Math.Min(requiredHeight, maximumDialogHeight)
_rtbMessage.Location = New Point(10, iconPictureBox.Height + 20) ' Set the location
_rtbMessage.ScrollBars = ScrollBars.Both
' Add the RichTextBox To the Form
_form.Controls.Add(_rtbMessage)
' PictureBox Parameters - For optional Graphics
Dim heightAdjustment As Integer = 0
If pictureBox IsNot Nothing Then
heightAdjustment += (_form.Width / 9) * 4
pictureBox.Width = _rtbMessage.Width
pictureBox.Height = heightAdjustment
heightAdjustment += buttonPadding * 2
' _form.Height += heightAdjustment + buttonPadding
pictureBox.BackColor = Color.Transparent
pictureBox.SizeMode = PictureBoxSizeMode.StretchImage
pictureBox.Location = New Point(10, _rtbMessage.Bottom + buttonPadding) ' Position below _rtbMessage
_form.Controls.Add(pictureBox)
End If
_form.Height = _rtbMessage.Bottom + 80 + heightAdjustment
' Buttons
Dim buttonWidth As Integer = 80
Dim buttonMargin As Integer = 10
Dim startX As Integer = (_form.Width - (buttonWidth + buttonMargin) - buttonPadding * 2)
Dim startY As Integer = _form.Height - buttonHeight - (buttonPadding * 2) - 30
If buttons = MessageBoxButtons.YesNo Then
Dim btnYes As New Button()
InitializeButton(btnYes, "Yes", startX, startY, buttonWidth, buttonHeight, AddressOf YesClick, _form)
startX -= buttonWidth + buttonMargin
btnYes.Select()
Dim btnNo As New Button()
InitializeButton(btnNo, "No", startX, startY, buttonWidth, buttonHeight, AddressOf NoClick, _form)
startX -= buttonWidth + buttonMargin
ElseIf buttons = MessageBoxButtons.OKCancel Then
Dim btnOK As New Button()
InitializeButton(btnOK, "OK", startX, startY, buttonWidth, buttonHeight, AddressOf OKClick, _form)
startX -= buttonWidth + buttonMargin
btnOK.Select()
Dim btnCancel As New Button()
InitializeButton(btnCancel, "Cancel", startX, startY, buttonWidth, buttonHeight, AddressOf CancelClick, _form)
startX -= buttonWidth + buttonMargin
ElseIf buttons = MessageBoxButtons.OK Then
Dim btnOK As New Button()
InitializeButton(btnOK, "OK", startX, startY, buttonWidth, buttonHeight, AddressOf OKClick, _form)
startX -= buttonWidth + buttonMargin
btnOK.Select()
ElseIf buttons = MessageBoxButtons.YesNoCancel Then
Dim btnYes As New Button()
InitializeButton(btnYes, "Yes", startX, startY, buttonWidth, buttonHeight, AddressOf YesClick, _form)
startX -= buttonWidth + buttonMargin
btnYes.Select()
Dim btnNo As New Button()
InitializeButton(btnNo, "No", startX, startY, buttonWidth, buttonHeight, AddressOf NoClick, _form)
startX -= buttonWidth + buttonMargin
Dim btnCancel As New Button()
InitializeButton(btnCancel, "Cancel", startX, startY, buttonWidth, buttonHeight, AddressOf CancelClick, _form)
startX -= buttonWidth + buttonMargin
End If
' Label - For Timer Countdown
' If Duration has been set,start the Timer.
If duration > 0 Then
isTimerRunning = True
Dim _timerCountdownLabel As New Label
_timerCountdownLabel.Text = "00:00:00"
_timerCountdownLabel.Location = New Point(15, startY + 5)
' Add the Label To the Form
_form.Controls.Add(_timerCountdownLabel)
' Start the timer and update the countdown label
StartTimer(_timer, duration + 50, _form, _timerCountdownLabel)
End If
End Sub
Private Shared Sub InitializeButton(button As Button, text As String, x As Integer, y As Integer, width As Integer, height As Integer, clickHandler As EventHandler, form As Form)
button.Text = text
button.Width = width
button.Height = height
button.Location = New Point(x, y)
button.BackColor = Color.White
AddHandler button.Click, clickHandler
form.Controls.Add(button)
End Sub
Private Shared Sub YesClick(sender As Object, e As EventArgs)
_result = DialogResult.Yes
DirectCast(sender, Button).FindForm().Close()
End Sub
Private Shared Sub NoClick(sender As Object, e As EventArgs)
_result = DialogResult.No
DirectCast(sender, Button).FindForm().Close()
End Sub
Private Shared Sub CancelClick(sender As Object, e As EventArgs)
_result = DialogResult.Cancel
DirectCast(sender, Button).FindForm().Close()
End Sub
Private Shared Sub OKClick(sender As Object, e As EventArgs)
_result = DialogResult.OK
DirectCast(sender, Button).FindForm().Close()
End Sub
Private Shared Sub StartTimer(_timer As Timer, duration As Integer, form As Form, countdownLabel As Label)
_timer = New Timer()
Dim startTime As DateTime = Now
Dim endTime As DateTime = startTime.AddMilliseconds(duration)
_timer.Interval = 37
AddHandler _timer.Tick, Sub(sender As Object, e As EventArgs)
If Now() > endTime Then
_timer.Stop()
_timer.Dispose()
isTimerRunning = False
form.Close()
End If
Dim currentTime As DateTime = DateTime.Now
Dim timeRemaining As TimeSpan = endTime - currentTime
' Convert TimeSpan back to DateTime to extract hours, minutes, seconds, and milliseconds
Dim remainingDateTime As DateTime = DateTime.Today.Add(timeRemaining)
' Extract hours, minutes, seconds, and milliseconds
Dim hours As Integer = remainingDateTime.Hour
Dim minutes As Integer = remainingDateTime.Minute
Dim seconds As Integer = remainingDateTime.Second
Dim milliseconds As Integer = remainingDateTime.Millisecond
' Adjust for negative timeRemaining
If timeRemaining < TimeSpan.Zero Then
hours = 0
minutes = 0
seconds = 0
milliseconds = 0
End If
' Format the time as a string
Dim timeString As String = $"{hours:D2}:{minutes:D2}:{seconds:D2}.{milliseconds:D3}"
' Update the countdown label
countdownLabel.Text = timeString
End Sub
_timer.Start()
End Sub
Public Shared Function GetButtonClicked(ByVal passedResultCode As Integer) As String
Select Case passedResultCode
Case 0
Return "none"
Case 1
Return "OK"
Case 2
Return "Cancel"
Case 6
Return "Yes"
Case 7
Return "No"
Case Else
Return "UNKNOWN VALUE: " & passedResultCode
End Select
End Function
Public Shared Function ConvertPlainTextToRTF(formattedPlainText As String) As String
Dim richTextBox As New RichTextBox()
richTextBox.Rtf = formattedPlainText
Dim rtf As String = richTextBox.Rtf
richTextBox.Dispose() ' Dispose the RichTextBox after use
Return rtf
End Function
Public Shared Function ConvertRTFToPlainText(passedRtf As String) As String
Dim richTextBox As New RichTextBox()
richTextBox.Rtf = passedRtf
Dim rtfText As String = richTextBox.Rtf
richTextBox.Dispose() ' Dispose the RichTextBox after use
Return rtfText
End Function
End Class
Upvotes: 1
Reputation: 15774
You can create one dynamically
Public Module CustomMessageBox
Private result As String
Public Function Show(options As IEnumerable(Of String), Optional message As String = "", Optional title As String = "") As String
result = "Cancel"
Dim myForm As New Form With {.Text = title}
Dim tlp As New TableLayoutPanel With {.ColumnCount = 1, .RowCount = 2}
Dim flp As New FlowLayoutPanel()
Dim l As New Label With {.Text = message}
myForm.Controls.Add(tlp)
tlp.Dock = DockStyle.Fill
tlp.Controls.Add(l)
l.Dock = DockStyle.Fill
tlp.Controls.Add(flp)
flp.Dock = DockStyle.Fill
For Each o In options
Dim b As New Button With {.Text = o}
flp.Controls.Add(b)
AddHandler b.Click,
Sub(sender As Object, e As EventArgs)
result = DirectCast(sender, Button).Text
myForm.Close()
End Sub
Next
myForm.FormBorderStyle = FormBorderStyle.FixedDialog
myForm.Height = 100
myForm.ShowDialog()
Return result
End Function
End Module
You see you have options as to what buttons are present, the message, and title.
Use it like this
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim result = CustomMessageBox.Show(
{"Right", "Left"},
"Do you want to go right or left?",
"Confirm Direction")
MessageBox.Show(result)
End Sub
End Class
In my example, the prompt is "Do you want to go right or left?"
and the options are "Right"
and "Left"
.
The string is returned as opposed to DialogResult because now your options are unlimited (!). Experiment with the size to your suiting.
Upvotes: 6
Reputation: 5986
DialogResult
Enum for that. Here is a basic example i just wrote to demonstrate that, please see the comments i have added inside the code.
create a new project with 2 forms, Form1 will be the main form that will call the custom msgbox and Form2 will be the custom msgbox:
Form1:
Form2:
Code for Form1:
Public Class Form1
Private Sub btnOpenCustomMsgbox_Click(sender As Object, e As EventArgs) Handles btnOpenCustomMsgbox.Click
Dim customMsgbox = New Form2("this is my custom msg, if you press yes i will do something if you press no i will do nothing")
If customMsgbox.ShowDialog() = DialogResult.Yes Then
' do something
MsgBox("I am doing some operation...")
Else
' do nothing (its DialogResult.no)
MsgBox("I am doing nothing...")
End If
End Sub
End Class
Code for Form2:
Public Class Form2
' field that will contain the messege
Private PromtMsg As String
Sub New(ByVal promtmsg As String)
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
' set global field with the argument that was passed to the constructor
Me.PromtMsg = promtmsg
End Sub
Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
' set the msg label
Me.lblPromtMsg.Text = Me.PromtMsg
End Sub
Private Sub btnCustomYes_Click(sender As Object, e As EventArgs) Handles btnCustomYes.Click
' user choosed yes - return DialogResult.Yes
Me.DialogResult = DialogResult.Yes
Me.Close()
End Sub
Private Sub btnCustomNo_Click(sender As Object, e As EventArgs) Handles btnCustomNo.Click
' user choosed no - DialogResult.no
Me.DialogResult = DialogResult.No
Me.Close()
End Sub
End Class
it can be much more sophisticated but if you explore that example i hope you will understand the general idea.
Upvotes: 2