Skip to content

Processing of UI blocked #11

@labsin

Description

@labsin

When a task is awaited, the UI could repaint and trigger events. But this doesn't happen because _workItemsWaiting.WaitOne() also blocks the event queue of WPF windows. A DispatcherFrame can be pushed to continue the main dispatcher loop until this frame is canceled. That's how WPF synchronously waits for dialogs to return.

Should I propose a PR? I noticed this repo is somewhat stale.

It's available in net40 up and Windows desktop (WPF targets). So not on .net standard or Coree

Code that works for me:

private class ExclusiveSynchronizationContext : SynchronizationContext
{
    private bool _done;
    private EventQueue _items;
    private SynchronizationContext _old;
    private DispatcherFrame _dispatcherFrame;

    public Exception InnerException { get; set; }

    public ExclusiveSynchronizationContext(SynchronizationContext old)
    {
        _old = old;
        ExclusiveSynchronizationContext oldEx =
            old as ExclusiveSynchronizationContext;

        if (null != oldEx)
        {
            this._items = oldEx._items;
        }
        else
        {
            this._items = new EventQueue();
        }
    }

    public override void Send(SendOrPostCallback d, object state)
    {
        throw new NotSupportedException(
            "We cannot send to our same thread");
    }

    public override void Post(SendOrPostCallback d, object state)
    {
        _items.Enqueue(Tuple.Create(d, state));
        if (_dispatcherFrame != null)
        {
            _dispatcherFrame.Continue = false;
            _dispatcherFrame = null;
        }
    }

    public void EndMessageLoop()
    {
        Post(_ => _done = true, null);
    }

    public void BeginMessageLoop()
    {
        while (!_done)
        {
            EventTask task = null;

            if (!_items.TryDequeue(out task))
            {
                task = null;
            }

            if (task != null)
            {
                task.Item1(task.Item2);
                if (InnerException != null) // method threw an exeption
                {
                    throw new AggregateException(
                        "AsyncBridge.Run method threw an exception.",
                        InnerException);
                }
            }
            else
            {
                // No task to run, so we wait for the next post to cancel the dispatcher frame
                _dispatcherFrame = new DispatcherFrame();
                Dispatcher.PushFrame(_dispatcherFrame);
            }
        }
    }

    public override SynchronizationContext CreateCopy()
    {
        return this;
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions