views:

284

answers:

2

I am trying to write a VB.NET alternative to a C# anonymous function.

I wish to call Threading.SynchronizationContext.Current.Send which expects a delegate of type Threading.SendOrPostCallback to be passed to it. The background is here, but because I wish to both pass in a string to MessageBox.Show and also capture the DialogResult I need to define another delegate within. I am struggling with the VB.NET syntax, both from the traditional delegate style, and lambda functions.

My go at the traditional syntax is below, but I have gut feeling it should be much simpler than this:

Private Sub CollectMesssageBoxResultFromUserAsDelegate(ByVal messageToShow As String, ByRef wasCanceled As Boolean)
    wasCanceled = False
    If Windows.Forms.MessageBox.Show(String.Format("{0}{1}Please press [OK] to ignore this error and continue, or [Cancel] to stop here.", messageToShow), "Continue", Windows.Forms.MessageBoxButtons.OKCancel, Windows.Forms.MessageBoxIcon.Exclamation) = Windows.Forms.DialogResult.Cancel Then
        wasCanceled = True
    End If
End Sub


Private Delegate Sub ShowMessageBox(ByVal messageToShow As String, ByRef canceled As Boolean)


Private Sub AskUserWhetherToCancel(ByVal message As String, ByVal args As CancelEventArgs)

    If args Is Nothing Then args = New System.ComponentModel.CancelEventArgs With {.Cancel = False}

    Dim wasCancelClicked As Boolean
    Dim firstDelegate As New ShowMessageBox(AddressOf CollectMesssageBoxResultFromUserAsDelegate)
    '…. Now what??
    'I can’t declare SendOrPostCallback as below: 
    'Dim myDelegate As New Threading.SendOrPostCallback(AddressOf firstDelegate) 


End Sub
+1  A: 
magnifico
Correct, it will compile on its own, but how do I push the params (message, wasCancelClicked) into that. And then how would I call:Threading.SynchronizationContext.Current.Send(AddressOf myDelegate)If I do that I receive error: "'AddressOf' operand must be the name of a method (without parentheses)"
Topdown
+3  A: 

I think the easiest way to handle this is to create a new object which wraps the displaying of the message box. This object can then be used to retrieve the result.

For example:

Public Class Helper 
  Public WasCanceled as Boolean
  Public Message As String
  Public Done as New ManualResetEvent(false)
  Public Sub New(message as String) 
    Me.Message = message
  End Sub 
  Public Sub ShowMessageBox(unused as Object) 
    If MessageBox.Show(Message) = DialogResult.Cancel Then 
      WasCanceled = True
    Done.Set()
  End Sub 
End Class

Public Sub AskUserWhetherToCancel(context as SynchronizationContext, message As String)
  Dim helper As New Helper(message)
  context.Post(AddressOf helper.ShowMessageBox, Nothing)

  ' Wait for it to finish
  helper.WaitOne()

  if helper.WasCanceled Then 
    ...
  Else
    ...
  End IF
End Sub
JaredPar
Great, thanks Jared this worked well. I grabbed the SynchronizationContext of the form in the form constructor and used this as the context to Post to. I didn't need to WaitOne or use the ManualResetEvent because I was doing a Post (synchronous) rather than a Send (async). More refs to SynchronizationContext: http://blogs.msdn.com/mattdotson/archive/2006/02/13/531315.aspx and http://www.codeproject.com/KB/cpp/SyncContextTutorial.aspx
Topdown