1

The situation

I'll try to explain my Problem with a small example. I have a class that manages a view-stack. Replaces views shows and initializes them etc.

class ViewManager()
{
    void ReplaceView()
    {
        RemoveView(...);
        InitializeView(...); // this code may call Application.DoEvents()
        AddNewView(...);
    }

    void ShowModalView()
    {
        ShowView();
        Dispatcher.PushFrame()
        ....
        // wait until view can be removed
        RemoveView();
    }

   void RemoveView()
   {
     ...
   }
   // ... more functions
}

Because the ViewManager does a lot with UI elements, other Threads uses the ViewManager through Dispatcher.Invoke.

Dispatcher.Invoke(new Action(() => m_viewManager.Remove(someView)));

If now multiple threads Invoke actions on the ViewManager, and one of them calls deep down somewhere in the code Application.DoEvents or DispatcherPushFrame, a second MessageLoop is spawned that will invoke another method o n the view Manager.

The Problem:

  • ShowModalView is called and calls PushFrame.
  • During ShowModalView another thread calls ShowModalView or ReplaceView.
  • Because the new message loop executes all tasks queued to the dispatcher this method are also executed.
  • Therefore two methods of the ViewManager are executed "at the same time" - or better because it is the same thread - nested in each other.

Locking inside the ViewManager is useless, because it is all the same thread. A semaphore might freeze the UI thread, because during the Message loop of the "ShowModalView" another thread can invoke ShowModalView on the dispatcher and that will freeze the UI thread.

The Questions:

  • During the "ShowModalView" the UI thread should handle input / paint etc but should not handle other tasks invoked through "Dispatcher.Invoke" Is this possible?
  • Do you have other Ideas to solve this problem?

Thank you for your hints and answers

Manuel

EDIT: One solution might be to get rid of all DoEvents and PushFrame code. This is very hard to achieve but probably the only right solution. This post explains a part of my Problem

Use of Application.DoEvents

Community
  • 1
  • 1
Manuel Amstutz
  • 1,311
  • 13
  • 33
  • 1
    This is one of the main reasons why you shouldn't be using `DoEvents`, or their equivalent. It makes programming everything else in your application a *lot* harder. You should be using proper asynchrony, and offloading extended non-UI CPU bound work to a background thread, rather than using `DoEvents` or an equivalent. Rather than digging yourself deeper and deeping into a hole trying to hack yourself out of a hack, *fix the broken code*. – Servy Mar 14 '14 at 14:43
  • Yes i totally agree. I do all my work in Non-UI threads. But i've not yet found a solution to properly display a own type of a modal dialog that only handles User input an nothing else. The hard part is to find an appropriate replacement for all the code that currently uses Application.DoEvents(). But i think that's the way to go. – Manuel Amstutz Mar 14 '14 at 14:52
  • Create a window and call `ShowDialog` on it. Voila. – Servy Mar 14 '14 at 14:55

1 Answers1

0

As Servy said, get rid of Application.DoEvents() and Dispatcher.PushFrame is the only clean solution. Sometimes this will cause a lot of refactoring but it is worth the effort.

Manuel Amstutz
  • 1,311
  • 13
  • 33