Popup message queueing
I think instead of looping indefinitely over the queue you should only start it when the first popup is queued via the DisplayPopupmessage and loop only as long as there are any popups. After you've shown everything you should exit the loop and  start agian when something arrives.



For this job you should have a dedicated service that knows how to handle it. Currently it looks like the logic is within the popup-message.

I used these models for testing:

interface IPopupMessage
{
    string Message { get; }
    TimeSpan Timeout { get; }
}

class PopupMessage : IPopupMessage
{
    public string Message { get; set; }
    public TimeSpan Timeout { get; set; }
}


A simple service could be implemented like this one to handle the queue:

class PopupMessageService
{
    private bool _started;
    private readonly Queue&lt;IPopupMessage&gt; _popupMessageQueue = new Queue&lt;IPopupMessage&gt;();

    public void DisplayPopupMessage(IPopupMessage popup)
    {
        Console.WriteLine($"Equeued \"{popup.Message}\".");
        _popupMessageQueue.Enqueue(popup);
        Start();
    }

    private async void Start()
    {
        if (_started) { return; }
        _started = true;
        Console.WriteLine("Service started.");
        while (_popupMessageQueue.Any())
        {
            await Task.Run(async () =&gt;
            {
                var msg = _popupMessageQueue.Dequeue();
                Console.WriteLine($"Showing \"{msg.Message}\".");
                await Task.Delay(msg.Timeout);
            });
        }
        _started = false;
        Console.WriteLine("Service stopped.");
    }
}


The real message should have a method like Show(CacellationToken token) that you use to display the message and to hide it via the token.IsCancellationRequested and token.ThrowIfCancellationRequested(). You should handle the OperationCanceledException in order to proceed to the next popup.

It's just for demonstration purposes so I left the Console.WriteLine there.

And here's one more example how to use the above service:

void Main()
{
    Messages();
}

static async void Messages()
{
    var popupMessageService = new PopupMessageService();

    var messages = new IPopupMessage[]
    {
        new PopupMessage { Message = "Foo", Timeout = TimeSpan.FromSeconds(3) },
        new PopupMessage { Message = "Baz", Timeout = TimeSpan.FromSeconds(5) },
        new PopupMessage { Message = "Qux", Timeout = TimeSpan.FromSeconds(1) },
        new PopupMessage { Message = "Bar", Timeout = TimeSpan.FromSeconds(2) },
    };

    foreach (var msg in messages)
    {
        popupMessageService.DisplayPopupMessage(msg);

        // For test purposes assuming a message arrives every 3 seconds.
        await Task.Delay(TimeSpan.FromSeconds(3)); 
    }
}


The output is:

Equeued "Foo".
Service started.
Showing "Foo".
Service stopped.
Equeued "Baz".
Service started.
Showing "Baz".
Equeued "Qux".
Showing "Qux".
Service stopped.
Equeued "Bar".
Service started.
Showing "Bar".
Service stopped.