title: Show busy indicator if long running action is on ui thread
body: <p>I have my xaml:</p>
  
  <pre><code>        &lt;Window x:Class="Views.ShellView"
                  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                  xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
                  xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
                  Height="768" Width="1024" WindowStartupLocation="CenterScreen"
                  Title="{Binding Path=DisplayName}"&gt;
  
              &lt;xctk:BusyIndicator x:Name="BusyIndicator"  IsBusy="{Binding IsBusy, UpdateSourceTrigger=PropertyChanged}" &gt;
  
                  &lt;TreeView Style="{StaticResource TableSchemaTreeViewStyle}" ItemContainerStyle="{StaticResource SchemaTreeViewStyle}" Margin="0,15,0,0" 
                                    x:Name="TreeViewSchema" 
                                    TreeViewItem.Expanded="TreeViewSchema_OnExpanded" 
                                    TreeViewItem.Selected="TreeViewSchema_OnSelected" 
                                    Grid.Row="2" 
                                    ItemsSource="{Binding CurrentProject.Tables, Converter={StaticResource TreeViewSortingConverter}, ConverterParameter=FullTableName}"&gt;
                  &lt;/TreeView&gt;
  
              &lt;/xctk:BusyIndicator&gt;
          &lt;/Window&gt;
  </code></pre>
  
  <p>And suppose I have long running task in code-behind which is performed on UI thread (long filtering of treeview, it can have more then 1000 tables and each table more than 100 columns in it).</p>
  
  <p>Lets say I iterate and set <code>tableTreeViewItem.Visibility = Visibility.Collapsed;</code> for each item.</p>
  
  <p>What I want: show BusyIndicator by setting it to true before this action:</p>
  
  <p><code>BusyIndicator.IsBusy = true;</code>.</p>
  
  <p>The problem: both actions on UI thread and binding does not work as expected. I tried few things:</p>
  
  <pre><code>BusyIndicator.IsBusy = true;
  
  TaskScheduler uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
  
  Task.Factory.StartNew(() =&gt;
  {
  
      tableTreeViewItem.Visibility = Visibility.Collapsed;
  
  }, CancellationToken.None, TaskCreationOptions.None, uiScheduler).ContinueWith(task =&gt; Dispatcher.Invoke(() =&gt;
  {
      BusyIndicator.IsBusy = false;
  }));
  </code></pre>
  
  <p>And using dispatcher:</p>
  
  <pre><code>BusyIndicator.IsBusy = true;
  
  //long-running UI task
  tableTreeViewItem.Visibility = Visibility.Collapsed;
  
  BusyIndicator.IsBusy = false;
  </code></pre>
  
  <p>But it does not work, any ideas how to fix it?</p>
  
  <p>PSS</p>
  
  <p>I made some updates, I decided to grab all data and store which tree view item should be visible or hidden. </p>
  
  <p>So I have class which stores table, visibility and visible columns for filter method </p>
  
  <pre><code> class TreeViewItemVisibilityTableContainer
  {
      private TreeViewItem _treeViewItem;
      private TableModel _table;
      private Visibility _visibility;
      private List&lt;ColumnModel&gt; _visibleColumns;
  
      public TableModel Table
      {
          get { return _table; }
          set { _table = value; }
      }
      public TreeViewItem TreeViewItem
      {
          get { return _treeViewItem; }
          set { _treeViewItem = value; }
      }
      public Visibility Visibility
      {
          get { return _visibility; }
          set { _visibility = value; }
      }
      public List&lt;ColumnModel&gt; VisibleColumns
      {
          get { return _visibleColumns; }
          set { _visibleColumns = value; }
      }
  }
  </code></pre>
  
  <p>And now I can filter all this staff directly on UI thread:</p>
  
  <pre><code> System.Action filterTreeViewItemsVisibility = () =&gt; Dispatcher.Invoke(() =&gt;
              {
                  foreach (var item in itemsToFilter)
                  {
                      item.TreeViewItem.Visibility = item.Visibility;
                      var capturedItemForClosure = item;
  
                      if (item.Visibility == Visibility.Visible)
                      {
                          if (item.VisibleColumns.Any())
                          {
                              item.TreeViewItem.Items.Filter = item.TreeViewItem.Items.Filter =
                                  treeViewItem =&gt;
                                      capturedItemForClosure.VisibleColumns.Any(
                                          columnModel =&gt; columnModel.Equals(treeViewItem));
                          }
                          else
                          {
                              item.TreeViewItem.Visibility = Visibility.Collapsed;
                          }
                      }
                  }
              });
  
              IoC.Get&lt;IBusyIndicatorHelper&gt;().PerformLongrunningAction(filterTreeViewItemsVisibility, IoC.Get&lt;IShellViewModel&gt;());
  </code></pre>
  
  <p>But it is still super slow</p>