Sottotitoli di pulsanti personalizzati nella finestra di messaggio .NET?
-
04-07-2019 - |
Domanda
Esiste un modo semplice per visualizzare una finestra di messaggio in VB.NET con didascalie dei pulsanti personalizzate? Mi sono imbattuto in Qual è un modo semplice per creare un MessageBox con testo pulsante personalizzato in Managed C ++? , negli archivi Stack Overflow, ma è per C ++ gestito .
Soluzione
No, non esiste un metodo per accedere o reindirizzare il testo del pulsante predefinito del Messagebox.
L'unico modo per farlo è codificare il tuo o semplicemente usare uno dei tanti gratuiti da Internet:
Altri suggerimenti
No.
Dovrai creare un modulo personalizzato con FormBorderType = FixedDialog
.
Ecco un piccolo tutorial:
Creazione di finestre di dialogo in .NET
di James D. Murray il 12 giugno 2007, sotto 70-526
Esame di certificazione Microsoft: 70-526 (MCTS)
Obiettivo: creare e utilizzare finestre di dialogo personalizzate nelle applicazioni Windows Form.
Lingua: Visual Basic 2005 (fare clic qui per la versione C # di questa voce)
Ricordo la prima volta che avevo bisogno di creare una finestra di dialogo in un'applicazione .NET che stavo scrivendo in C #. Essendo un programmatore di Visual Basic da molto tempo, ho ipotizzato che ciò potesse essere facilmente realizzato utilizzando un modello di finestra di dialogo incluso in Visual Studio.NET. Con mia sorpresa, non esisteva un modello di modulo simile per C #, anche se uno lo fa per Visual Basic 2005. Dopo aver consultato diversi libri e pagine Web pieni di informazioni sulla programmazione di Windows Forms 2.0, mi è apparso una serie di passaggi per convertire manualmente un Modulo .NET in una finestra di dialogo di Windows:
Passaggio 1: aggiungi un modulo al tuo progetto .NET e chiamalo & # 8220; DialogBoxForm & # 8221 ;.
Passaggio 2: rilascia due pulsanti nell'area in basso a destra del modulo e chiamali & # 8220; OKButton & # 8221; e & # 8220; CancelButton & # 8221 ;.
Passaggio 3: modifica le seguenti proprietà del modulo per modificarne l'aspetto e il comportamento in modo che siano simili a una finestra di dialogo standard:
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.
Queste proprietà possono essere impostate utilizzando la finestra Proprietà per il modulo o utilizzando il codice inserito nell'evento Load del modulo:
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
Passaggio 4: aggiungere i seguenti gestori di eventi clic sui pulsanti al modulo:
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
Passaggio 5: aggiungi le proprietà necessarie per spostare i dati dentro e fuori dalla finestra di dialogo come faresti per qualsiasi modulo:
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
Passaggio 6: mostra modalmente la finestra di dialogo chiamando ShowDialog () del modulo:
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
Passaggio 7: per mostrare la finestra di dialogo in modo non modale, chiamare invece il metodo Show () di DialogBoxForm. Sarà necessario aggiungere un gestore eventi all'evento Chiudi di DialogBoxForm per sapere quando l'utente chiude la finestra di dialogo:
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
MessageBox utilizza una semplice finestra che può essere rovinata come qualsiasi altra finestra. Questo è stato possibile in Windows per molto tempo, già da oltre 20 anni. Le tecniche stanno diventando oscure, troppi wrapper di classe amichevoli che nascondono il winapi nativo e non espongono tutto ciò che puoi farci. Al punto che i programmatori ora assumono automaticamente che ciò non sia possibile, come si può vedere dalle risposte votate. È il tipo di programmazione che Petzold ci ha insegnato nella sua "Programmazione di Windows" seminale libro. Sostituire MessageBox con un modulo o una finestra personalizzati è in realtà abbastanza difficile da fare, fa un layout automatico non banale per adattarsi al testo e supporta la localizzazione senza aiuto. Anche se è esattamente quello che non ti piace :)
Anyhoo, la finestra della finestra di messaggio è facile da trovare. È di proprietà del thread dell'interfaccia utente e ha un nome di classe speciale che lo rende unico. EnumThreadWindows () enumera le finestre di proprietà di un thread, GetClassName () consente di verificare il tipo di finestra. Quindi basta inserire il testo nel pulsante con SetWindowText ().
Aggiungi una nuova classe al tuo progetto e incolla il codice mostrato di seguito. Invocalo con un codice come questo:
Nobugz.PatchMsgBox(New String() {"Da", "Njet"})
MsgBox("gack", MsgBoxStyle.YesNo)
Ecco il codice:
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
C'è una soluzione. Tramite l'installazione di un hook CBT è possibile regolare al volo una vasta gamma di impostazioni visive di MessageBox: font di messaggi e pulsanti, sfondo delle finestre di dialogo, posizionamento dei dialoghi, icone, didascalie dei pulsanti, timeout, persino inserendo controlli aggiuntivi.
Soluzione completa: Extended MessageBox .NET Assembly http://www.news2news.com/vfp/?solution=5
È una versione di prova completamente funzionale, la versione normale include il codice sorgente C # completo.
Il codice C # per realizzare la stessa cosa può essere trovato in un articolo nel forum MSDN, https://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=3087899&SiteID=1 .
Aggiungilo al pulsante da cui vuoi mostrare la finestra di dialogo. Questo è un modulo personalizzato 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");
}
}
Aggiungi questo codice a 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();
}
La soluzione di Daniel Nolan, codice in 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
Ecco uno snippet C # che utilizza un hook Win32 per modificare le didascalie dei pulsanti (provenienti da 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);
}