.NET 消息框中的自定义按钮标题?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/234774/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Custom button captions in .NET messagebox?
提问by subrama6
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++.
有没有一种简单的方法可以在 VB.NET 中显示带有自定义按钮标题的消息框?我遇到了在 Managed C++ 中创建带有自定义按钮文本的 MessageBox 的简单方法是什么?, 在 Stack Overflow 档案中,但它用于Managed C++。
采纳答案by PersistenceOfVision
No there is no method to access or redirect the Messagebox's default button text.
不,没有方法可以访问或重定向消息框的默认按钮文本。
The only way to do this is to code your own or just use one of many free ones from the internet:
做到这一点的唯一方法是编写自己的代码或仅使用互联网上的许多免费代码之一:
回答by BradC
No.
You'll have to make a custom form with FormBorderType = FixedDialog.
Here is a little tutorial:
不,
您必须使用FormBorderType = FixedDialog.
这是一个小教程:
Creating Dialog Boxes in .NET
在 .NET 中创建对话框
by James D. Murray on Jun.12, 2007, under 70-526
作者:James D. Murray,2007 年 6 月 12 日,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)
Microsoft 认证考试:70-526 (MCTS)
目标:在 Windows 窗体应用程序中创建和使用自定义对话框。
语言:Visual Basic 2005(单击此处获取本条目的 C# 版本)
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:
我记得我第一次需要在我用 C# 编写的 .NET 应用程序中创建一个对话框。作为一名长期的 Visual Basic 程序员,我认为这可以通过使用 Visual Studio.NET 中包含的对话框模板轻松完成。令我惊讶的是,C# 不存在这样的表单模板,尽管 Visual Basic 2005 存在这样的表单模板。在翻阅了几本充满 Windows Forms 2.0 编程信息的书籍和网页后,我对手动转换表单的一组基本步骤变得很明显。 .NET 形式进入 Windows 对话框:
Step 1 : Add a Form to your .NET project and name it “DialogBoxForm”.
第 1 步:向您的 .NET 项目添加一个表单并将其命名为“DialogBoxForm”。
Step 2 : Drop two buttons in the lower right-hand area of the Form and name them “OKButton” and “CancelButton”.
第 2 步:在 Form 的右下方区域放置两个按钮,并将它们命名为“OKButton”和“CancelButton”。
Step 3 : Change the following properties of the Form to adjust its appearance and behavior to be like a standard dialog box:
第 3 步:更改 Form 的以下属性以将其外观和行为调整为类似于标准对话框:
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:
可以使用表单的“属性”窗口或使用放置在表单的 Load 事件中的代码来设置这些属性:
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:
第 4 步:将以下按钮单击事件处理程序添加到 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:
步骤 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
Step 6 : Show the dialog box modally by calling the ShowDialog() of the form:
第 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
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:
步骤 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
回答by Hans Passant
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 :)
MessageBox 使用一个普通的窗口,可以像任何其他窗口一样使用它。这在 Windows 中已经实现了很长时间,已经超过 20 年了。但是,这些技术变得越来越模糊,太多友好的类包装器隐藏了本机 winapi 并且不公开您可以用它做的所有事情。如此之多以至于程序员现在自动假设这是不可能的,正如您从赞成的答案中可以看出的那样。这是 Petzold 在其开创性的“Programming Windows”一书中教给我们的那种编程。用自定义的 Form 或 Window 替换 MessageBox 实际上相当困难,它执行非平凡的自动布局以适应文本并支持本地化而无需帮助。虽然这正是你似乎不喜欢的:)
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().
Anyhoo,消息框窗口很容易找回来。它归 UI 线程所有,并具有使其独一无二的特殊类名。EnumThreadWindows() 枚举线程拥有的窗口,GetClassName() 可让您检查窗口的类型。然后只需使用 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
回答by Anatoliy Mogylevets
There is a solution. Via installing a CBT hook it is possible to adjust a wide variety of MessageBox visual settings on the fly: message and button fonts, dialog background, dialog positioning, icons, button captions, timeout, even inserting additional controls.
有一个解决方案。通过安装 CBT 钩子,可以动态调整各种 MessageBox 视觉设置:消息和按钮字体、对话框背景、对话框定位、图标、按钮标题、超时,甚至插入其他控件。
Complete solution: Extended MessageBox .NET Assembly http://www.news2news.com/vfp/?solution=5
完整解决方案:Extended MessageBox .NET Assembly http://www.news2news.com/vfp/?solution=5
It is a fully-functional trial version, the regular version includes complete C# source code.
它是一个功能齐全的试用版,普通版包含完整的 C# 源代码。
回答by Miguel Yskatll
The solution by Daniel Nolan, code in VB.Net
Daniel Nolan 的解决方案,VB.Net 中的代码
<DllImport("kernel32.dll")> _
Private Shared Function GetCurrentThreadId() As UInteger
End Function
<DllImport("user32.dll", CharSet:=CharSet.Auto)> _
Private Shared Function CallNextHookEx(ByVal idHook As Integer, ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
End Function
<DllImport("user32.dll", CharSet:=CharSet.Auto)> _
Private Shared Function UnhookWindowsHookEx(ByVal idHook As Integer) As Boolean
End Function
<DllImport("user32.dll", CharSet:=CharSet.Auto)> _
Private Shared Function SetWindowsHookEx(ByVal idHook As Integer, ByVal lpfn As HookProc, ByVal hInstance As IntPtr, ByVal threadId As Integer) As Integer
End Function
<DllImport("user32.dll")> _
Private Shared Function SetDlgItemText(ByVal hWnd As IntPtr, ByVal nIDDlgItem As Integer, ByVal lpString As String) As Boolean
End Function
Private Delegate Function HookProc(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
Shared dlgHookProc As HookProc
Private Const WH_CBT As Long = 5
Private Const HCBT_ACTIVATE As Long = 5
Private Const ID_BUT_OK As Integer = 1
Private Const ID_BUT_CANCEL As Integer = 2
Private Const ID_BUT_ABORT As Integer = 3
Private Const ID_BUT_RETRY As Integer = 4
Private Const ID_BUT_IGNORE As Integer = 5
Private Const ID_BUT_YES As Integer = 6
Private Const ID_BUT_NO As Integer = 7
Private Const BUT_OK As String = "Save"
Private Const BUT_CANCEL As String = "Cancelar"
Private Const BUT_ABORT As String = "Stop"
Private Const BUT_RETRY As String = "Continue"
Private Const BUT_IGNORE As String = "Ignore"
Private Const BUT_YES As String = "Si"
Private Const BUT_NO As String = "No"
Private Shared _hook As Integer = 0
Private Shared Function DialogHookProc(ByVal nCode As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
If nCode < 0 Then
Return CallNextHookEx(_hook, nCode, wParam, lParam)
End If
If nCode = HCBT_ACTIVATE Then
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)
End If
Return CallNextHookEx(_hook, nCode, wParam, lParam)
End Function
Private Sub btn_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn.Click
dlgHookProc = New HookProc(AddressOf DialogHookProc)
_hook = SetWindowsHookEx(CInt(WH_CBT), dlgHookProc, IntPtr.op_Explicit(0), CInt(GetCurrentThreadId()))
Dim dlgEmptyCheck As DialogResult = MessageBox.Show("Text", "Caption", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button3)
If dlgEmptyCheck = DialogResult.Abort Then
End If
UnhookWindowsHookEx(_hook)
End Sub
回答by Tassaduq
Add this to the button that you want the dialog to be shown from. This is a custom form messageBox;
将此添加到您希望显示对话框的按钮。这是一个自定义表单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");
}
}
Add this code to messageBox.
将此代码添加到 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();
}
回答by balexandre
C# code to accomplish the same thing can be found in an article under MSDN forum, https://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=3087899&SiteID=1.
可以在 MSDN 论坛下的一篇文章https://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=3087899&SiteID=1 中找到完成同样事情的 C# 代码。
回答by Dan Nolan
Here is a C# snippet that uses a Win32 hook to alter the button captions (sourced from http://icodesnip.com/snippet/csharp/custom-messagebox-buttons):
这是一个 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);
}

