ManualResetEvent WaitOne blocks the owner Thread of my CollectionView

c#, dispatcher, manualresetevent, nunit, wpf

Solution

As I see the main problem that main thread is blocked and other operations are trying to be executed in main thread too? What about not to block main thread, like this:

// helper functions
public void DoEvents()
{
    DispatcherFrame frame = new DispatcherFrame();
    Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background,
        new DispatcherOperationCallback(ExitFrame), frame);
    Dispatcher.PushFrame(frame);
}

public object ExitFrame(object f)
{
    ((DispatcherFrame)f).Continue = false;

    return null;
}

// in your code:  
while(!_dialogClosed.WaitOne(200)) 
    DoEvents();

If it will not help then I guess need to try some SynchronisationContext workarounds.

Problem

I've written a WPF WizardFramework which performs some actions in the background using some `BackgroundWorker`. While processing it can happen that I have to update an `ObservableCollection` which is bound to my UI. For this case I've written a `ThreadableObservableCollection`, which provides threadsafe methods for `Insert`, `Remove` and `RemoveAt`. Though I'm using .NET 4.5 I was not able to get `BindingOperations.EnableCollectionSynchronization` working without many other invalid access exceptions. My `Collection` looks like: ``` public class ThreadableObservableCollection<T> : ObservableCollection<T> { private readonly Dispatcher _dispatcher; public ThreadableObservableCollection() { _dispatcher = Dispatcher.CurrentDispatcher; } public void ThreadsafeInsert(int pos, T item, Action callback) { if (_dispatcher.CheckAccess()) { Insert(pos, item); callback(); } else { _dispatcher.Invoke(() => { Insert(pos, item); callback(); }); } } [..] } ``` This is working as expected, while I am using the wizard in my application. Now I'm using NUnit to write some integrationtests for the application. There's a listener which waits for the WizardViewModel to finish it's work and looking for some pages which are injected in the Steps-Collection. After the asyncrone work is done I can use Validate to check the viewmodel state. Unfortunately I'm using a `ManualResetEvent` to wait for the wizard to close. This looks like following: ``` public class WizardValidator : IValidator, IDisposable { private WizardViewModel _dialog; private readonly ManualResetEvent _dialogClosed = new ManualResetEvent(false); [..] public void ListenTo(WizardViewModel dialog) { _dialog = dialog; dialog.RequestClose += (sender, args) => _dialogClosed.Set(); dialog.StepsDefaultView.CurrentChanged += StepsDefaultViewOnCurrentChanged; _dialogClosed.WaitOne(); } [..] } ``` Now there's a problem: While the Application is running the UI Thread is not blocked, the Collection can be updated without any problems. But in my testcases the "main" Thread where I initialize the ViewModel (and because of that the Collections) is an AppDomainThread which is blocked by the testcode. Now my `ThreadsafeInsert` wants to update the collection but cannot use the AppDomain Thread. But I have to wait for the wizard to finish, how can I solve this kind of deadlock? Or is there a more elegant solution for this one? edit: I worked around this problem with a check if there's a user interface, and only then I invoke on the Application-Thread, otherwise I change the collection intentionally on another thread. This does not prevent the exception, but it is not recognized from the test... the items are inserted nevertheless, only the `NotifyCollectionChanged`-Handler is not called (which is only used in the UI anyway). ``` if (Application.Current != null) { Application.Current.Dispatcher.Invoke(() => { Steps.Insert(pos, step); stepsView.MoveCurrentTo(step); }); } else { new Action(() => Steps.Insert(pos, step)).BeginInvoke(ar => stepsView.MoveCurrentToPosition(pos), null); } ``` This is an ugly workaround and I am still interested in a clean solution. Is there a way to use an alternate Dispatcher to create (e.g.) the whole ViewModel and use this to change my collection?

Original source

Related problems