Why is Window.ShowDialog not blocking in TaskScheduler Task?
c#, multithreading, task-parallel-library
Solution
Nothing obviously wrong. Except what is missing, you are not doing anything to ensure that an exception that's raised in the task is reported. The way you wrote it, such an exception will never be reported and you'll just see code failing to run. Like a dialog that just disappears. You'll need to write something like this:
Task.Factory.StartNew(() => {
// Your code here
//...
}, CancellationToken.None, TaskCreationOptions.None, taskScheduler)
.ContinueWith((t) => {
MessageBox.Show(t.Exception.ToString());
}, TaskContinuationOptions.OnlyOnFaulted);
With good odds that you'll now see an InvalidOperationException reported. Further diagnose it with Debug + Exceptions, tick the Thrown checkbox for CLR exceptions.
Do beware that this task scheduler doesn't magically makes your code thread-safe or fit to run another UI thread. It wasn't made for that, it should only be used to keep single-threaded COM components happy. You must honor the sometimes draconian consequences of running UI on another thread. In other words, don't touch properties of UI on the main thread. And the dialog not acting like a dialog at all since it doesn't have an owner. And it thus randomly disappearing behind another window or accidentally getting closed by the user because he was clicking away and never counted on a window appearing from no-where.
And last but not least the long-lasting misery caused by the SystemEvents class. Which needs to guess which thread is the UI thread, it will pick the first STA thread. If that's your dialog then you'll have very hard to diagnose threading problems later.
Don't do it.
Problem
I'm using a custom `TaskScheduler` to execute a task queue in serial. The task is supposed to display a window and then block until the window closes itself. Unfortunately calling `Window.ShowDialog()` doesn't seem to block so the task completes and the window never displays. If I put a breakpoint after the call to `ShowDialog` I can see the form has opened but under normal execution the Task seems to end so quickly you cant see it. My TaskScheduler implementation taken from a 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); ```