是否有一种简单的方法可以在VB.NET中使用自定义按钮标题显示消息框?我在Stack Overflow存档中遇到了 What is an easy way to create a MessageBox with custom button text in Managed C++? ,但它是Managed C++。
答案 0 :(得分:18)
没有。
您必须使用FormBorderType = FixedDialog
制作自定义表单。
这是一个小教程:
作者: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)
答案 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&id=613','asdasd');
String[] asd = new String[2];
asd[0] = "groups.php?opt=del&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);
}