title: Task.Run apparently locks UI when nested too deep
body: <p>I have a WPF application that needs to parse a bunch of large XML files (around 40MB) containing products and save information about all products that are actually books. For progress reporting, I have a datagrid that displays the filename, status ("waiting", "parsing", "completed", that sort of thing), number of products found, number of parsed products, and number of books found, like this:</p>
  
  <pre><code>        &lt;DataGrid Grid.ColumnSpan="2" Grid.Row="1" ItemsSource="{Binding OnixFiles}" AutoGenerateColumns="False" 
                CanUserAddRows="False"
                CanUserDeleteRows="False"
                CanUserReorderColumns="False"
                CanUserResizeColumns="False"
                CanUserResizeRows="False"
                CanUserSortColumns="False"&gt;
          &lt;DataGrid.Columns&gt;
              &lt;DataGridTextColumn Header="Bestand" IsReadOnly="True" Binding="{Binding FileName}" SortMemberPath="FileName" /&gt;
              &lt;DataGridTextColumn Header="Status" IsReadOnly="True" Binding="{Binding Status}" /&gt;
              &lt;DataGridTextColumn Header="Aantal producten" IsReadOnly="True" Binding="{Binding NumTotalProducts}" /&gt;
              &lt;DataGridTextColumn Header="Verwerkte producten" IsReadOnly="True" Binding="{Binding NumParsedProducts}" /&gt;
              &lt;DataGridTextColumn Header="Aantal geschikte boeken" IsReadOnly="True" Binding="{Binding NumSuitableBooks}" /&gt;                
          &lt;/DataGrid.Columns&gt;
      &lt;/DataGrid&gt;
  </code></pre>
  
  <p>When I hit the "Parse" button, I want to iterate through the list of filenames and parse each file, reporting the amount of products, parsed products and found books along the way. Obviously I want my UI to remain responsive so I want to do the parsing on a different thread using Task.Run().</p>
  
  <p>When the user hits a button labeled "Parse", the application needs to start parsing the files. If I call TaskRun right in the button command's command_executed method everything works fine:</p>
  
  <pre><code>    private async void ParseFilesCommand_Executed(object sender, ExecutedRoutedEventArgs e)
      {
          foreach (var f in OnixFiles)
          {
              await Task.Run(() =&gt; f.Parse());
          }
      }
  
      // In the OnixFileViewModel
      public void Parse()
      {
          var progressIndicator = new Progress&lt;ParsingProgress&gt;(ReportProgress);
          var books = Parser.ParseFile(this.fileName, progressIndicator);
      }
  
      private void ReportProgress(ParsingProgress progress)
      {
          // These are properties that notify the ui of changes
          NumTotalProducts = progress.NumTotalProducs;
          NumParsedProducts = progress.NumParsedProducts;
          NumSuitableBooks = progress.NumSuitableBooks;
      }
  
      // In the class Parser
  public static IEnumerable&lt;Book&gt; ParseFile(string filePath, IProgress&lt;ParsingProgress&gt; progress)
      {
          List&lt;Book&gt; books = new List&lt;Book&gt;();
  
          var root = XElement.Load(filePath);
          var fileInfo = new FileInfo(filePath);
          XNamespace defaultNamespace = "http://www.editeur.org/onix/3.0/reference";
  
          var products = (from p in XElement.Load(filePath).Elements(defaultNamespace + "Product")
                          select p).ToList();
  
          var parsingProgress = new ParsingProgress()
          {
              NumParsedProducts = 0,
              NumSuitableBooks = 0,
              NumTotalProducs = products.Count
          };
  
          progress.Report(parsingProgress);
  
          foreach (var product in products)
          {
              // Complex XML parsing goes here
              parsingProgress.NumParsedProducts++;
  
              if (...) // If parsed product is actual book
              {  
                  parsingProgress.NumSuitableBooks++;                 
              }
  
              progress.Report(parsingProgress);
          }
  
          return books;
      }
  </code></pre>
  
  <p>It all executes super-fast, the ui gets updated quickly and remains responsive. However, if I move the call to Task.Run() into the ParseFile method, like so:</p>
  
  <pre><code>    private async void ParseFilesCommand_Executed(object sender, ExecutedRoutedEventArgs e)
      {
          foreach (var f in OnixFiles)
          {
              await f.ParseAsync();
          }
      }
  
      // In the OnixFileViewModel
      public async Task ParseAsync()
      {
          var progressIndicator = new Progress&lt;ParsingProgress&gt;(ReportProgress);
          var books = await Parser.ParseFileAsync(this.fileName, progressIndicator);
      }
  
      private void ReportProgress(ParsingProgress progress)
      {
          // These are properties that notify the ui of changes
          NumTotalProducts = progress.NumTotalProducs;
          NumParsedProducts = progress.NumParsedProducts;
          NumSuitableBooks = progress.NumSuitableBooks;
      }
  
      // In the class Parser
  public static async Task&lt;IEnumerable&lt;Book&gt;&gt; ParseFileAsync(string filePath, IProgress&lt;ParsingProgress&gt; progress)
      {
          List&lt;Book&gt; books = new List&lt;Book&gt;();
  
          await Task.Run(() =&gt;
          {
  
          var root = XElement.Load(filePath);
          var fileInfo = new FileInfo(filePath);
          XNamespace defaultNamespace = "http://www.editeur.org/onix/3.0/reference";
  
          var products = (from p in XElement.Load(filePath).Elements(defaultNamespace + "Product")
                          select p).ToList();
  
          var parsingProgress = new ParsingProgress()
          {
              NumParsedProducts = 0,
              NumSuitableBooks = 0,
              NumTotalProducs = products.Count
          };
  
          progress.Report(parsingProgress);
  
          foreach (var product in products)
          {
              // Complex XML parsing goes here
              parsingProgress.NumParsedProducts++;
  
              if (...) // If parsed product is actual book
              {  
                  parsingProgress.NumSuitableBooks++;                 
              }
  
              progress.Report(parsingProgress);
          }
          });
  
          return books;
      }
  </code></pre>
  
  <p>The UI locks up, doesn't update until after a file has finished parsing, and everything appears much slower.</p>
  
  <p>What am I missing? Why does it work as expected if you call Task.Run() in the command_executed handler, but not if you call it in an async method called by that method?</p>
  
  <p><strong>Edit:</strong> as requested by Shaamaan, here's a simpler sample of what I'm doing (using simply thread.sleep to simulate workload) but frustratingly, the sample works like I had originally expected it to, failing to highlight the problem I'm having. Still, adding it for completeness:</p>
  
  <p>MainWindow.xaml:</p>
  
  <pre><code>&lt;Window x:Class="ThreadingSample.MainWindow"
          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
          Title="MainWindow" Height="350" Width="525"&gt;
      &lt;StackPanel&gt;
  
          &lt;DataGrid Grid.ColumnSpan="2" Grid.Row="1" ItemsSource="{Binding Things}" AutoGenerateColumns="False" 
                    Height="250"
                    CanUserAddRows="False"
                    CanUserDeleteRows="False"
                    CanUserReorderColumns="False"
                    CanUserResizeColumns="False"
                    CanUserResizeRows="False"
                    CanUserSortColumns="False"&gt;
              &lt;DataGrid.Columns&gt;
                  &lt;DataGridTextColumn Header="Name" IsReadOnly="True" Binding="{Binding Name}" /&gt;
                  &lt;DataGridTextColumn Header="Value" IsReadOnly="True" Binding="{Binding Value}" /&gt;                
              &lt;/DataGrid.Columns&gt;
          &lt;/DataGrid&gt;
  
          &lt;Button Click="RightButton_Click"&gt;Right&lt;/Button&gt;
          &lt;Button Click="WrongButton_Click"&gt;Wrong&lt;/Button&gt;
      &lt;/StackPanel&gt;
  &lt;/Window&gt;
  </code></pre>
  
  <p>MainWindow.xaml.cs:</p>
  
  <pre><code>using System;
  using System.Collections.Generic;
  using System.Collections.ObjectModel;
  using System.Linq;
  using System.Text;
  using System.Threading;
  using System.Threading.Tasks;
  using System.Windows;
  using System.Windows.Controls;
  using System.Windows.Data;
  using System.Windows.Documents;
  using System.Windows.Input;
  using System.Windows.Media;
  using System.Windows.Media.Imaging;
  using System.Windows.Navigation;
  using System.Windows.Shapes;
  
  namespace ThreadingSample
  {
      /// &lt;summary&gt;
      /// Interaction logic for MainWindow.xaml
      /// &lt;/summary&gt;
      public partial class MainWindow : Window
      {
          public ObservableCollection&lt;Thing&gt; Things { get; private set; }
  
          public MainWindow()
          {
              InitializeComponent();
  
              this.DataContext = this;
  
              Things = new ObservableCollection&lt;Thing&gt;();
  
              for (int i = 0; i &lt; 200; i++)
              {
                  Things.Add(new Thing(i));
              }
          }
  
          private async void RightButton_Click(object sender, RoutedEventArgs e)
          {
              foreach (var t in Things)
              {
                  await Task.Run(() =&gt; t.Parse());
              }
          }
  
          private async void WrongButton_Click(object sender, RoutedEventArgs e)
          {
              foreach (var t in Things)
              {
                  await t.ParseAsync();
              }            
          }
      }
  }
  </code></pre>
  
  <p>Thing.cs:</p>
  
  <pre><code>using System;
  using System.Collections.Generic;
  using System.ComponentModel;
  using System.Linq;
  using System.Text;
  using System.Threading;
  using System.Threading.Tasks;
  
  namespace ThreadingSample
  {
      public class Thing : INotifyPropertyChanged
      {
          private string _name;
  
          public string Name
          {
              get { return _name; }
              set
              {
                  _name = value;
                  RaisePropertyChanged("Name");
              }
          }
  
          private int _value;
  
          public int Value
          {
              get { return _value; }
              set
              {
                  _value = value;
                  RaisePropertyChanged("Value");
              }
          }
  
          public Thing(int number)
          {
              Name = "Thing nr. " + number;
              Value = 0;
          }
  
          public void Parse()
          {
              var progressReporter = new Progress&lt;int&gt;(ReportProgress);
              HeavyParseMethod(progressReporter);
          }
  
          public async Task ParseAsync()
          {
              var progressReporter = new Progress&lt;int&gt;(ReportProgress);
              await HeavyParseMethodAsync(progressReporter);
          }
  
          private void HeavyParseMethod(IProgress&lt;int&gt; progressReporter)
          {
              for (int i = 0; i &lt; 1000; i++)
              {
                  Thread.Sleep(10);
                  progressReporter.Report(i);
              }
          }
  
          private async Task HeavyParseMethodAsync(IProgress&lt;int&gt; progressReporter)
          {
              await Task.Run(() =&gt;
                  {
                      for (int i = 0; i &lt; 1000; i++)
                      {
                          Thread.Sleep(100);
                          progressReporter.Report(i);
                      }
                  });
          }
  
          private void ReportProgress(int progressValue)
          {
              this.Value = progressValue;
          }
  
          private void RaisePropertyChanged(string propertyName)
          {
              if (PropertyChanged != null)
              {
                  PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
              }
          }
  
          public event PropertyChangedEventHandler PropertyChanged;
      }
  }
  </code></pre>
  
  <p>The only difference between this sample and my real-life code, that I can tell, is that my real-life code parses a bunch of 40mb xml files using LINQ to XML whereas this sample just calls Thread.Sleep().</p>
  
  <p><strong>Edit 2:</strong> I've found a horrifying workaround. If I use the second method and call Thread.Sleep(1) after each product is parsed and before calling IProgress.Report(), everything works fine. I can see the "NumParsedProducts" counter increase and everything. This is a terrible hack though. What could it mean?</p>