Why doesn't Window.ShowDialog block the TaskScheduler task?

I use custom TaskSchedulerto execute a task queue in sequential order. The task is supposed to display a window and then lock until the window closes. Unfortunately, the call Window.ShowDialog()does not seem to be blocked, so the task ends and the window is never displayed.

If I set a breakpoint after the call ShowDialog, I see that the form is open, but in normal execution the task seems to end so quickly that you cannot see it.

My TaskScheduler implementation taken from the previous question:

public sealed class StaTaskScheduler : TaskScheduler, IDisposable
{
    private readonly List<Thread> threads;
    private BlockingCollection<Task> tasks;

    public override int MaximumConcurrencyLevel
    {
        get { return threads.Count; }
    }

    public StaTaskScheduler(int concurrencyLevel)
    {
        if (concurrencyLevel < 1) throw new ArgumentOutOfRangeException("concurrencyLevel");

        this.tasks = new BlockingCollection<Task>();
        this.threads = Enumerable.Range(0, concurrencyLevel).Select(i =>
        {
            var thread = new Thread(() =>
            {
                foreach (var t in this.tasks.GetConsumingEnumerable())
                {
                    this.TryExecuteTask(t);
                }
            });
            thread.IsBackground = true;
            thread.SetApartmentState(ApartmentState.STA);
            return thread;
        }).ToList();

        this.threads.ForEach(t => t.Start());
    }

    protected override void QueueTask(Task task)
    {
        tasks.Add(task);
    }
    protected override IEnumerable<Task> GetScheduledTasks()
    {
        return tasks.ToArray();
    }
    protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
    {
        return Thread.CurrentThread.GetApartmentState() == ApartmentState.STA && TryExecuteTask(task);
    }

    public void Dispose()
    {
        if (tasks != null)
        {
            tasks.CompleteAdding();

            foreach (var thread in threads) thread.Join();

            tasks.Dispose();
            tasks = null;
        }
    }
}

My application code:

private StaTaskScheduler taskScheduler;

...

this.taskScheduler = new StaTaskScheduler(1);

Task.Factory.StartNew(() =>
{
    WarningWindow window = new WarningWindow(
        ProcessControl.Properties.Settings.Default.WarningHeader,
        ProcessControl.Properties.Settings.Default.WarningMessage,
        processName,
        ProcessControl.Properties.Settings.Default.WarningFooter,
        ProcessControl.Properties.Settings.Default.WarningTimeout * 1000);
    window.ShowDialog();

}, CancellationToken.None, TaskCreationOptions.None, this.taskScheduler);
+4
source share
3

. , , , , , . , , , , . , . - :

    Task.Factory.StartNew(() => {
        // Your code here
        //...
    }, CancellationToken.None, TaskCreationOptions.None, taskScheduler)
    .ContinueWith((t) => {
        MessageBox.Show(t.Exception.ToString());
    }, TaskContinuationOptions.OnlyOnFaulted);

, InvalidOperationException. Debug + Exceptions, "" CLR.

, . , , COM- . . , . , . , , , , - .

, - , SystemEvents. , , STA. .

.

+4

-, Stephen Toub StaTaskScheduler. , . , window.ShowDialog() , . , window.ShowDialog() , . :

try
{
    await Task.Factory.StartNew(() =>
    {
        WarningWindow window = new WarningWindow(
            ProcessControl.Properties.Settings.Default.WarningHeader,
            ProcessControl.Properties.Settings.Default.WarningMessage,
            processName,
            ProcessControl.Properties.Settings.Default.WarningFooter,
            ProcessControl.Properties.Settings.Default.WarningTimeout * 1000);
        window.ShowDialog();

    }, CancellationToken.None, TaskCreationOptions.None, this.taskScheduler);

}
catch(Exception ex)
{
    MessageBox.Show(ex.Message)
}

STA , Dispatcher:

    var task = Task.Factory.StartNew(() =>
    {
        System.Windows.Threading.Dispatcher.InvokeAsync(() =>
        {
            WarningWindow window = new WarningWindow(
                ProcessControl.Properties.Settings.Default.WarningHeader,
                ProcessControl.Properties.Settings.Default.WarningMessage,
                processName,
                ProcessControl.Properties.Settings.Default.WarningFooter,
                ProcessControl.Properties.Settings.Default.WarningTimeout * 1000);

            window.Closed += (s, e) =>
                window.Dispatcher.InvokeShutdown();
            window.Show();
        });

        System.Windows.Threading.Dispatcher.Run();

    }, CancellationToken.None, TaskCreationOptions.None, this.taskScheduler);

, . , StaTaskScheduler, , Dispatcher.Run().

+2

, ShowDialog. , , . , . , , , , .

0

Source: https://habr.com/ru/post/1526745/


All Articles