1

For some reason my program needs to pause in a function, while still reacting to user input. This is currently done using DoEvents in a loop.

Unfortunately my textbox does not work properly while I am in the DoEvents loop. I cannot type in it. It seems to get the KeyDown and KeyUp events OK, but the Text property and the dispaly do not show what I am typing.

To make matters more mysterious it reacts to backspace and Ctrl+V to paste text, just typing in it does not work. It works again OK as soon as I stop the loop.

Any ideas?

Attached is an example demonstrating the problem. Just in case it matters I am using VB on VS2010.

This is the xaml file:

<Window x:Class="MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="200" Width="200">
    <StackPanel>
        <TextBox x:Name="txtTest" Text="Testing" Margin="10"/>
        <Button x:Name="btnStartLoop" Content="Start DoEvents Loop"         
                Click="StartLoop_Click" Margin="10"/>
        <Button x:Name="btnStopLoop" Content="Stop DoEvents Loop" 
                Click="StopLoop_Click" Margin="10"/>
    </StackPanel>
</Window>

This is the xaml.vb file:

Class MainWindow
    Private stopLoop As Boolean = False

    Private Sub StartLoop_Click(ByVal sender As System.Object, 
                                ByVal e As System.Windows.RoutedEventArgs)
        stopLoop = False
        LoopFunction()
    End Sub

    Private Sub LoopFunction()
        While stopLoop = False
            System.Windows.Forms.Application.DoEvents()
            System.Threading.Thread.Sleep(1)
        End While
    End Sub

    Private Sub StopLoop_Click(ByVal sender As System.Object, 
                               ByVal e As System.Windows.RoutedEventArgs)
        stopLoop = True
    End Sub
End Class
César
  • 9,939
  • 6
  • 53
  • 74
Margarita
  • 11
  • 1

2 Answers2

1

I think you shouldn't use Application.DoEvents for this purpose. WPF has its own mechanizm for event processing via Dispatchers so I think you should use Dispatcher to process messages. Dispatchers have their own message queues and I assume that WPF sends some messages directly to the Dispatcher ignoring Windows message queue.

If you still want to use DoEvents-like hack I would recommend using this instead:

Dispatcher.BeginInvoke(new Action(() => {}), DispatcherPriority.Background);

And other separate question here is why do you want to use such a hacky approach here? Halting the main thread is not a good idea in Windows world anyway.

Snowbear
  • 16,924
  • 3
  • 43
  • 67
  • Good question about why I am using the DoEvents loop. I have been wondering whether there would be an alternative approach. My program is a kind a debugger. The code that executes (a standard C dll) uses callbacks to notify the VB.NET frontend of its progress. When the user wants to break execution, I need to loop in the frontend without returning from the callback function. I still need to react to user input. The whole code was ported from VB6, where the Windows message loop was replaced by a message loop within the program. – Margarita Nov 30 '11 at 13:37
  • I did try adding `Dispatcher.Invoke(DispatcherPriority.Render, New Action(AddressOf EmptyMethod))` in the loop, but that didn't help. – Margarita Nov 30 '11 at 13:43
  • Do you know of an example that uses Dispatchers to process messages instead of using DoEvents? – Margarita Nov 30 '11 at 13:46
  • @Margarita, http://kentb.blogspot.com/2008/04/dispatcher-frames.html. You've used `Render` priority which is pretty high priority (http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcherpriority.aspx), you should use lower priority, I think you can choose `ApplicationIdle` for example – Snowbear Nov 30 '11 at 14:36
  • you are a star!! Changing the priority made all the difference. I had used Render, because somewhere else in the progem we use the same line to specifically update the display and I just copied and pasted the line. I might still look a bit more into the Dispatcher to see if I can impriove the design. – Margarita Nov 30 '11 at 16:14
0

Take a look at ElementHost.EnableModelessKeyboardInterop(Window) method, it will make your wpf window's control work correctly when use Winform's DoEvent fuction.

alex.pulver
  • 2,107
  • 2
  • 31
  • 31