MessageBox.Show не вызывает событие HelpRequested

У меня есть форма, которая показывает MessageBox с помощью MessageBox.Show и пытается получать события от кнопки «Справка» в MessageBox, чтобы я мог выполнить свой собственный код. Документация Microsoft показывает, как это сделать; однако использование того, что предлагается, не работает. Вот сокращенная версия моего кода:

    Private Function MethodName() As Boolean

      AddHandler Me.HelpRequested, AddressOf Me.MsgBoxHelpRequested
      Select Case MessageBox.Show("Text", "Title", MessageButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2, 0, True)
        Case MsgBoxResult.Yes
          ' Do stuff
        Case MsgBoxResult.No
          ' Do stuff
        Case MsgBoxResult.Cancel
          RemoveHandler Me.HelpRequested, AddressOf Me.MsgBoxHelpRequested
          Return False
      End Select
      RemoveHandler Me.HelpRequested, AddressOf Me.MsgBoxHelpRequested

    End Function

Private Sub MsgBoxHelpRequested(ByVal sender As Object, ByVal hlpevent As System.Windows.Forms.HelpEventArgs)
  ' Breakpoint that never gets hit
  ' More code
End Sub

Я искал решение этой проблемы, но лучшее, что я нашел, это этот вопрос: Как обнаружить нажатие кнопки "Справка" в Windows Forms MessageBox? это отсылает меня к тому же коду Microsoft, который, похоже, не работает.

Может ли кто-нибудь помочь мне с этим?

Спасибо.


person Trevortni    schedule 12.05.2010    source источник
comment
Кстати, вы должны удалить обработчик события в блоке Finally, а не удалять его дважды.   -  person SLaks    schedule 13.05.2010
comment
@AMissico: это не опечатка. (Сам обработчик события не входит в блок Finally)   -  person SLaks    schedule 13.05.2010
comment
remove =› move: добавьте оператор Try...Finally и удалите обработчик событий в блоке finally. Это гарантирует, что обработчик будет удален после того, как вы вернете False или при любой потенциальной ошибке. В дополнение к комментарию SLaks о том, что его не нужно удалять дважды. Обратите внимание, что вам не нужно включать блок Catch   -  person AMissico    schedule 13.05.2010
comment
@Trevortni: если вы вызовете MethodName для конструктора формы (новый) или в событии Load формы, ваш образец кода не будет работать. Может поэтому у вас не работает.   -  person AMissico    schedule 13.05.2010
comment
@Trevortni: конструктор Sub New. Вы должны быть осторожны с некоторыми инициализациями в конструкторе или в событии Load формы. Причина в том, что дескриптор элемента управления, который включает в себя форму, еще не создан. Если вы работаете с тестовым проектом, то сравните тестовый проект с тем, что у вас есть. Подумайте, как вы вызываете методы и где. Наиболее вероятная причина, по которой ваше приложение не работает, связана с тем, что обработчик не добавлен, потому что форма не создана. (Он создается, когда форма становится видимой. Вы можете попробовать добавить form.CreateControl непосредственно перед добавлением обработчика.)   -  person AMissico    schedule 13.05.2010
comment
@Trevortni: Более того, попробуйте добавить обработчик на форму через дизайнер. Это гарантирует, что обработчик назначен правильно. (Пример MSDN делает все вручную и не является хорошим примером. Пример VB должен показать вам, как сделать это простым способом VB, а не более сложным ручным способом.)   -  person AMissico    schedule 13.05.2010


Ответы (4)


Передайте Me в качестве первого параметра для MessageBox.Show.

Добавьте обработчик в Form.ActiveForm вместо Me.

person SLaks    schedule 12.05.2010
comment
Не уверен, что это нужно. Мой образец работает без явной передачи this. - person MusiGenesis; 13.05.2010
comment
@MusiGenesis: только если this является активной формой. - person SLaks; 13.05.2010
comment
На самом деле, поскольку вы явно добавляете обработчик, вам не нужно передавать параметр Owner. - person AMissico; 13.05.2010
comment
@AMissico: я говорю о вызове MessageBox.Show. Это не имеет ничего общего с обработчиком. - person SLaks; 13.05.2010
comment
@SLaks. Упс. Вы правы, теперь, когда я снова смотрю на код. Он работает с и без, поэтому я сделал вывод, что это не требуется, потому что обработчик был явно добавлен. - person AMissico; 13.05.2010
comment
@SLaks: если что-то, кроме активной формы, показывает окна сообщений, у этого приложения могут быть другие проблемы. - person MusiGenesis; 13.05.2010

Это C#, и через секунду я автоматически переведу его на VB.

Поместите этот код в событие Load вашей формы:

this.HelpRequested += new HelpEventHandler(Form1_HelpRequested);

Затем добавьте этот код в форму:

void Form1_HelpRequested(object sender, HelpEventArgs hlpevent)
{
    hlpevent.Handled = true; // this will prevent windows from also opening
        // any associated help file
    // do whatever you're gonna do here
}

Затем вызовите MessageBox следующим образом:

MessageBox.Show("message", "caption", MessageBoxButtons.OK, 
    MessageBoxIcon.Asterisk,
    MessageBoxDefaultButton.Button1, 0, true);

Появится окно сообщения с кнопками OK и HELP. При нажатии кнопки HELP будет вызвана форма Form1_HelpRequested.

Версия VB.Net:

Поместите этот код в событие Load вашей формы:

AddHandler Me.HelpRequested, AddressOf Form1_HelpRequested 

Затем добавьте этот код в форму:

Private Sub Form1_HelpRequested(ByVal sender As Object, ByVal hlpevent As 
    HelpEventArgs) 
    ' this will prevent windows from also opening 
    ' any associated help file:
    hlpevent.Handled = True 
    ' do whatever you're gonna do here 
End Sub

Затем вызовите MessageBox следующим образом:

MessageBox.Show("message", "caption", MessageBoxButtons.OK, 
    MessageBoxIcon.Asterisk, MessageBoxDefaultButton.Button1, 0, _ 
    True)

Появится окно сообщения с кнопками OK и HELP. При нажатии кнопки HELP будет вызвана форма Form1_HelpRequested.

person MusiGenesis    schedule 12.05.2010

Если вы вызываете MethodName для конструктора формы (новый) или в событии Load формы, ваш образец кода не будет работать. Может поэтому у вас не работает.

Конструктор Sub New. Вы должны быть осторожны с некоторыми инициализациями в конструкторе или в событии Load формы. Причина в том, что дескриптор элемента управления, который включает в себя форму, еще не создан. Если вы работаете с тестовым проектом, то сравните тестовый проект с тем, что у вас есть. Подумайте, как вы вызываете методы и где. Наиболее вероятная причина, по которой ваше приложение не работает, связана с тем, что обработчик не добавлен, потому что форма не создана. (Он создается, когда форма становится видимой. Вы можете попробовать добавить form.CreateControl непосредственно перед добавлением обработчика.)

Более того, попробуйте добавить обработчик на форму через дизайнер. Это гарантирует, что обработчик назначен правильно. (Пример MSDN делает все вручную и не является хорошим примером. Пример VB должен показать вам, как сделать это простым способом VB, а не более сложным ручным способом.)

Public Class Form1
    Inherits System.Windows.Forms.Form

#Region " Designer-Generated "

    'Form overrides dispose to clean up the component list. 
    <System.Diagnostics.DebuggerNonUserCode()> _
    Protected Overrides Sub Dispose(ByVal disposing As Boolean)
        Try
            If disposing AndAlso components IsNot Nothing Then
                components.Dispose()
            End If
        Finally
            MyBase.Dispose(disposing)
        End Try
    End Sub
    Friend WithEvents Button2 As System.Windows.Forms.Button

    'Required by the Windows Form Designer 
    Private components As System.ComponentModel.IContainer

    'NOTE: The following procedure is required by the Windows Form Designer 
    'It can be modified using the Windows Form Designer.   
    'Do not modify it using the code editor. 
    <System.Diagnostics.DebuggerStepThrough()> _
    Private Sub InitializeComponent()
        Me.Button1 = New System.Windows.Forms.Button
        Me.Button2 = New System.Windows.Forms.Button
        Me.SuspendLayout()
        '
        'Button1
        '
        Me.Button1.Location = New System.Drawing.Point(0, 0)
        Me.Button1.Name = "Button1"
        Me.Button1.Size = New System.Drawing.Size(75, 23)
        Me.Button1.TabIndex = 0
        Me.Button1.Text = "Button1"
        Me.Button1.UseVisualStyleBackColor = True
        '
        'Button2
        '
        Me.Button2.Location = New System.Drawing.Point(0, 29)
        Me.Button2.Name = "Button2"
        Me.Button2.Size = New System.Drawing.Size(75, 23)
        Me.Button2.TabIndex = 1
        Me.Button2.Text = "Button2"
        Me.Button2.UseVisualStyleBackColor = True
        '
        'Form1
        '
        Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
        Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
        Me.ClientSize = New System.Drawing.Size(292, 266)
        Me.Controls.Add(Me.Button2)
        Me.Controls.Add(Me.Button1)
        Me.Name = "Form1"
        Me.Text = "Form1"
        Me.ResumeLayout(False)

    End Sub
    Friend WithEvents Button1 As System.Windows.Forms.Button

#End Region

    Public Sub New()
        ' This call is required by the Windows Form Designer. 
        InitializeComponent()
        ' Add any initialization after the InitializeComponent() call. 
        MethodName() 'will not work here 
    End Sub

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        MethodName() 'will not work here 
        'Me.CreateControl()
        MethodName2() 'still will not work 
    End Sub

    Private Function MethodName() As Boolean
        AddHandler Me.HelpRequested, AddressOf Me.MsgBoxHelpRequested
        Select Case MessageBox.Show("Text", "Title", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2, 0, True)
            Case Windows.Forms.DialogResult.Yes
                ' Do stuff  
            Case Windows.Forms.DialogResult.No
                ' Do stuff  
            Case Windows.Forms.DialogResult.Cancel
                RemoveHandler Me.HelpRequested, AddressOf Me.MsgBoxHelpRequested
                Return False
        End Select
        RemoveHandler Me.HelpRequested, AddressOf Me.MsgBoxHelpRequested
    End Function

    Private Function MethodName2() As Boolean
        AddHandler Me.HelpRequested, AddressOf Me.MsgBoxHelpRequested2
        Select Case MessageBox.Show("Text", "Title", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2, 0, True)
            Case Windows.Forms.DialogResult.Yes
                ' Do stuff  
            Case Windows.Forms.DialogResult.No
                ' Do stuff  
            Case Windows.Forms.DialogResult.Cancel
                RemoveHandler Me.HelpRequested, AddressOf Me.MsgBoxHelpRequested2
                Return False
        End Select
        RemoveHandler Me.HelpRequested, AddressOf Me.MsgBoxHelpRequested2
    End Function


    ''' <summary>
    '''  AddHandler Me.HelpRequested, AddressOf Module1.MsgBoxHelpRequested3
    ''' </summary>
    Private Function MethodName3() As Boolean
        AddHandler Me.HelpRequested, AddressOf Module1.MsgBoxHelpRequested3
        Select Case MessageBox.Show("Text", "Title", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button3, 0, True)
            Case Windows.Forms.DialogResult.Yes
                ' Do stuff  
            Case Windows.Forms.DialogResult.No
                ' Do stuff  
            Case Windows.Forms.DialogResult.Cancel
                RemoveHandler Me.HelpRequested, AddressOf Module1.MsgBoxHelpRequested3
                Return False
        End Select
        RemoveHandler Me.HelpRequested, AddressOf Module1.MsgBoxHelpRequested3
    End Function

    Private Sub MsgBoxHelpRequested(ByVal sender As Object, ByVal hlpevent As System.Windows.Forms.HelpEventArgs)
        ' Breakpoint that never gets hit  
        MsgBox("Here I am to save the day!")
    End Sub

    Private Sub MsgBoxHelpRequested2(ByVal sender As Object, ByVal hlpevent As System.Windows.Forms.HelpEventArgs)
        ' Breakpoint that never gets hit  
        MsgBox("Shoot, still now working.")
    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        MethodName() 'always works because all handles are created 
    End Sub

    Private Sub Form1_HelpRequested(ByVal sender As System.Object, ByVal hlpevent As System.Windows.Forms.HelpEventArgs) Handles MyBase.HelpRequested
        MsgBox("Always works! No need to add a handler because of Handles MyBase.HelpRequested.")
    End Sub

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        MethodName3()
    End Sub

End Class

Module Module1

    Public Sub MsgBoxHelpRequested3(ByVal sender As Object, ByVal hlpevent As System.Windows.Forms.HelpEventArgs)
        MsgBox("Being handled in a module.")
    End Sub

End Module
person AMissico    schedule 12.05.2010

Как оказалось, активным было другое окно, а не форма, вызывающая MessageBox. Поскольку ни одна версия MessageBox.Show не позволяет одновременно обрабатывать событие HelpRequested И указывать владельца, MessageBox искал в ActiveForm получателя события, а не отправлял его в мою форму. Внесение следующего изменения наконец-то заработало:

Private Function MethodName() As Boolean

  Me.Activate() ' <-------------------!!!!!!!!!

  AddHandler Me.HelpRequested, AddressOf Me.MsgBoxHelpRequested
  Select Case MessageBox.Show("Text", "Title", MessageButtons.YesNoCancel, _
            MessageBoxIcon.Question, MessageBoxDefaultButton.Button2, 0, True)
    Case MsgBoxResult.Yes
      ' Do stuff
    Case MsgBoxResult.No
      ' Do stuff
    Case MsgBoxResult.Cancel
      RemoveHandler Me.HelpRequested, AddressOf Me.MsgBoxHelpRequested
      Return False
  End Select
  RemoveHandler Me.HelpRequested, AddressOf Me.MsgBoxHelpRequested
End Function


Private Sub MsgBoxHelpRequested(ByVal sender As Object, _
            ByVal hlpevent As System.Windows.Forms.HelpEventArgs)
  ' Breakpoint that **finally** gets hit
  ' More code
End Sub

Есть еще ряд вещей, которые я буду исправлять с помощью этого кода, относящегося к другим вещам, но, безусловно, приятно, наконец, разобраться с этим.

Спасибо всем, кто помог.

person Trevortni    schedule 13.05.2010
comment
Извините, что портю вам настроение, но Me.Activate() нет гарантии фактической активации вашей формы. Просмотрите документы для SetForegroundWindow, чтобы увидеть правила. - person Hans Passant; 16.05.2010