8

I've read that the C# version is as follows:

Application.Current.Dispatcher.Invoke(
          DispatcherPriority.Background,
          new Action(delegate { }));

However I cannot figure out how to put the empty delegate into VB.NET, as VB.NET does not appear to support anonymous methods. Ideas?

Edit: Possibly this?

Application.Current.Dispatcher.Invoke(
  DispatcherPriority.Background,
  New Action(Sub()

             End Sub))
NibblyPig
  • 51,118
  • 72
  • 200
  • 356
  • DoEvents? I believe they used to DoEvents back in VB6, before people realized an application could have more than just the UI thread. –  Apr 19 '10 at 12:36
  • Well the modern convention is to use Thread.Sleep(1) or similar, but this doesn't work when you need to jump out of a thread temporarily to allow the UI to update itself and remain in the middle of a processing loop in WPF. – NibblyPig Apr 19 '10 at 12:38
  • 1
    @SLC: If you're doing your processing in another thread, then you shouldn't need to tell the UI to update itself (in just a general refresh kind of way). – Adam Robinson Apr 19 '10 at 12:40
  • 1
    You have to interrupt the UI thread to inform it to update a progress bar, which is possible in windows forms using the Invoke method but I believe it's different in WPF which is why this method is used... but I honestly know nothing about WPF and am just converting C# to VB. – NibblyPig Apr 19 '10 at 12:42
  • I have this in my app in one place. The problem is that Thread.Sleep(1) and Thread.Join() also block the Dispatcher queue. In my app, I have a second thread where a lot of the work is done. During the Application-Exit event, I shutdown that thread and wait until it finishes. However, since that thread also touches some of the UI objects, the Dispatcher queue has to stay alive. Thus, DoEvents is needed. – Daniel Rose Apr 19 '10 at 12:47
  • @Will it's not like there's NEVER a use for it (http://bea.stollnitz.com/blog/?p=59) – Rob Fonseca-Ensor Apr 20 '10 at 05:55
  • Does this answer your question? [Where is the Application.DoEvents() in WPF?](https://stackoverflow.com/questions/4502037/where-is-the-application-doevents-in-wpf) – StayOnTarget Mar 03 '21 at 18:37

5 Answers5

6

VB.NET does support anonymous delegates, but only as single-statement functions. (Multi-statement anonymous functions and anonymous Subs have been added to VB10 in .NET 4)

To provide context, DoEvents was designed to allow a single-threaded environment to update the UI and process other Windows messages while work was being done. There should be no benefit to calling DoEvents (or, as you're doing here, doing so indirectly by executing a "null" function on the dispatcher) from another thread, as the UI thread should be updating by itself.

In the interest of answering your question, though, the easiest option would be something like this:

Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, _
    New Action(Function() 7))

But, again, I can't see what this would actually accomplish.

If what you're looking for is simply how to execute code on the UI thread (like the Control.Invoke from Windows forms), then Dispatcher.Invoke (which is what you're using) is correct, you'll just have to translate your inline anonymous methods into discreet functions and pass those as delegates. There may be some that you can get away with leaving as anonymous. For example, if all you're doing is updating a progress bar, you could do:

Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, _
    New Action(Function() progressBar.Value = 100))

This works because all assignments return the value that was stored in the left side of the assignment. You could not, however, just call a sub like this (the following won't compile unless SomeFunctionName returns a value):

Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, _
    New Action(Function() SomeFunctionName(params)))

In other words, any of the anonymous delegates that are in the C# code that either:

  • Are more than one statement
  • Do not return a value (meaning it's just a single call to a method, not a function)

Then you'll have to create functions for those and pass delegates to those functions rather than inlining the code as you have in C#.

Adam Robinson
  • 182,639
  • 35
  • 285
  • 343
  • The UI can only update if it gets chance to though, which is at the end of a function. This is why your app becomes unresponsive if you put a loop into it, and even with a thread sleep will not update UI components in a loop without doing an Invoke in windows forms to force a switch to the other thread. I speculate this is the same. – NibblyPig Apr 19 '10 at 12:53
  • You can change Function() to Sub() and just have an empty Sub() as I speculated in my edit, because I just confirmed it in code and it seems to work. – NibblyPig Apr 19 '10 at 12:59
  • 3
    @SLC: This is only true if what you're doing is *taking place on the UI thread*. If the code is executing on another thread, then this is not necessary. **If what you're doing *is* executing on the UI thread and it's taking long enough to require an explicit UI update, then it should be moved to another thread.** – Adam Robinson Apr 19 '10 at 13:00
  • @SLC: The `Sub` option only works in VB10 (VisualStudio 2010/.NET 4). – Adam Robinson Apr 19 '10 at 13:01
  • Robinson - moving operations to another thread is not always practicable. In cases where you are loading a FlowDocument from a serialized XAML form, for example, you cannot produce it on the BG thread and then display it on the UI thread. It must be created and loaded on the UI thread. – Cheeso Aug 26 '11 at 17:02
4

You could simply call this method if you want something to be refreshed on the UI:

System.Windows.Forms.Application.DoEvents

We are using it on our WPF Window and XBAP applications.

Jojo Sardez
  • 8,400
  • 3
  • 27
  • 38
1

You've got two questions here, so i'm going to add two answers. Here, i'm answering "how to do DoEvents in WPF". Bea Stollnitz covers this on her blog, and here's the code in VB:

publicShared Sub WaitForPriority(priority As DispatcherPriority)
    Dim frame As New DispatcherFrame()
    Dim dispatcherOperation As DispatcherOperation = Dispatcher.CurrentDispatcher.BeginInvoke(priority, New DispatcherOperationCallback(ExitFrameOperation), frame)
    Dispatcher.PushFrame(frame)
    If dispatcherOperation.Status <> DispatcherOperationStatus.Completed Then
        dispatcherOperation.Abort()
    End If
End Sub

Private Shared Function ExitFrameOperation(obj As Object) As Object
    (DirectCast(obj, DispatcherFrame)).[Continue] = False
    Return Nothing
End Function
Rob Fonseca-Ensor
  • 15,510
  • 44
  • 57
1

or Simply use dispatcher to make yourself a Doevents() for WPF:

    'The WPF equivalent of DoEvents!!
Public Sub DoEvents()
    Dispatcher.Invoke(New Action(Function()
                                     Return Nothing
                                 End Function), DispatcherPriority.ContextIdle, Nothing)
End Sub
okThen
  • 11
  • 1
0

Use the Function keyword:

Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, New Action(Function() Do ... End Function))
Rob Fonseca-Ensor
  • 15,510
  • 44
  • 57