-2

When I am use Thread.Sleep in UpdateGuItemsAsync program freez for 10 second because thread is blocked. If I use Task.Delay in 'UpdateGuItemsAsync' code executes immediately without pause. I expect to get delay before list update without UI freezing. How to do this in .net 3.5?

TaskScheduler uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
Task.Factory.StartNew(UpdateGuItemsAsync, CancellationToken.None, TaskCreationOptions.None, uiScheduler);


    public void UpdateGuItemsAsync()
    {
        System.Threading.Thread.Sleep(10000);
        for (int i = 0; i < 100; i++)
        {
            Gu45Document gu45Document = new Gu45Document();
            gu45Document.Form = "EU-45";
            Gu45Documents.Add(gu45Document);
        }
    }
A191919
  • 3,422
  • 7
  • 49
  • 93
  • If your UI code is Wpf i can advise to you look to UI main thread `Dispatcher`. http://stackoverflow.com/questions/11625208/accessing-ui-main-thread-safely-in-wpf – Oğuzhan Soykan Oct 21 '16 at 22:31
  • 1
    Doing `Task.Factory.StartNew` with `TaskScheduler.FromCurrentSynchronizationContext();` called on the UI thread is the same thing as running the code on the UI thread directly. No multi-threading is involved here. – Scott Chamberlain Oct 21 '16 at 22:36

4 Answers4

3

You can use System.Windows.Forms.Timer which will not block the UI while waiting 10 seconds :

 public void UpdateGuItemsAsync()
 {
    System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
    timer.Interval = 10000;
    timer.Tick += (sender, args) => 
    {
        timer.Stop();
        for (int i = 0; i < 100; i++)
        {
            Gu45Document gu45Document = new Gu45Document();
            gu45Document.Form = "EU-45";
            Gu45Documents.Add(gu45Document);
        }
    };
    timer.Start();  
 }
YuvShap
  • 3,825
  • 2
  • 10
  • 24
  • I would put the `timer.Stop();` before the `for` loop so you don't accidentally queue up a 2nd firing of the tick event if your `for` loop takes too long to process. – Scott Chamberlain Oct 21 '16 at 23:16
1

EDIT

Sorry, I missed the point about .Net 3.5 cause the Task.Delay talk. Below find an example in .net 3.5 that updates a progressbar in a form after 10 secs. when pressing a button in that form:

using System;
using System.Threading;
using System.Windows.Forms;

  public partial class Form1 : Form
  {
    public Form1()
    {
      InitializeComponent();
    }

    delegate void UpdateGuItemsAsyncDelegate();
    void UpdateGuItemsAsync()
    {
      for (int i = 0; i < 100; i++)
      {
        progressBar1.PerformStep();
      }
    }

    private void button1_Click(object sender, EventArgs e)
    {
      ThreadPool.QueueUserWorkItem(state =>
      {
        Thread.Sleep(10000);

        if (progressBar1.InvokeRequired)
        {
          UpdateGuItemsAsyncDelegate del = new UpdateGuItemsAsyncDelegate(UpdateGuItemsAsync);
          this.Invoke(del);
        }
        else
        {
          UpdateGuItemsAsync();
        }

      });
    }
  }

In WPF/XAML you can do almost the same if you have a progressbar and a button in your Window:

  <StackPanel>
    <ProgressBar Name="ProgBar" Minimum="0" Maximum="100" Height="20" />
    <Button Name="UpdateCmd" Click="UpdateCmd_Click" Content="Update" />
  </StackPanel>

And in code:

private void UpdateCmd_Click(object sender, RoutedEventArgs e)
{
  ThreadPool.QueueUserWorkItem(state =>
  {
    Thread.Sleep(10000);

    for (int i = 0; i < 100; i++)
    {
      Dispatcher.Invoke(new Action(() =>
      {
        ProgBar.Value++;
      }));

      Thread.Sleep(50);
    }
  });
}
1

In your situation what I would do is use a System.Windows.Threading.DispatcherTimer and have it run a event after 10 seconds. This will work with both WPF and WinForms however if your project is winforms you will need to add a reference to WindowsBase in your project references.

private void UpdateGuItemsAsync()
{
    //This line must be called on the UI thread
    var timer = new DispatcherTimer();
    timer.Interval = TimeSpan.FromSeconds(10);
    timer.Tick += OnUpdateGuiItemsTimerTick;
    timer.Start();
}

private void OnUpdateGuiItemsTimerTick(object sender, EventArgs e)
{
    //Stop the timer.
    var timer = sender as DispatcherTimer;
    timer.Stop();

    //Run the code you where waiting for.
    for (int i = 0; i < 100; i++)
    {
        Gu45Document gu45Document = new Gu45Document();
        gu45Document.Form = "EU-45";
        Gu45Documents.Add(gu45Document);
    }
}

Below is a stand alone program you and run in .NET 3.5 to see that it works. All you need to do is create a new windows forms project, add a reference to WindowsBase and use the below code

using System;
using System.Windows.Forms;
using System.Windows.Threading;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            this.Load += Form1_Load;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            UpdateGuiItems();
        }

        private void UpdateGuiItems()
        {
            var timer = new DispatcherTimer();
            timer.Interval = TimeSpan.FromSeconds(5);
            timer.Tick += OnUpdateGuiItemsTimerTick;
            timer.Start();
        }

        private void OnUpdateGuiItemsTimerTick(object sender, EventArgs e)
        {
            var timer = sender as DispatcherTimer;
            timer.Stop();

            MessageBox.Show("Am I on the UI thread: " + !this.InvokeRequired);
        }
    }
}
Scott Chamberlain
  • 124,994
  • 33
  • 282
  • 431
0

This should do the job

TaskScheduler uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
Task.Factory.StartNew( () => Thread.Sleep( 10000 ) )
    .ContinueWith(
        t => UpdateGuItemsAsync(),
        CancellationToken.None,
        TaskContinuationOptions.None,
        uiScheduler );

public void UpdateGuItemsAsync()
{
    // System.Threading.Thread.Sleep(10000);
    for (int i = 0; i < 100; i++)
    {
        Gu45Document gu45Document = new Gu45Document();
        gu45Document.Form = "EU-45";
        Gu45Documents.Add(gu45Document);
    }
}

I am using the NuGet Package Task Parallel Library for .NET 3.5.

Sir Rufo
  • 18,395
  • 2
  • 39
  • 73
  • `Task.Delay` does not exist in .NET 3.5 (actually the entire `System.Threading.Tasks` namespace does not exist in 3.5) – Scott Chamberlain Oct 21 '16 at 22:55
  • Well the OP self mentioned he testet it with `Task.Delay` - I think he has included the TPL NuGet package – Sir Rufo Oct 21 '16 at 22:57
  • I did not know that any NuGet packages existed for that. However, I don't believe that is the case here. I think the OP tested in .NET 4.0 or in 4.5 but wants to know how to solve the problem in 3.5 – Scott Chamberlain Oct 21 '16 at 23:00
  • Ok, I edited my answer - now tested with .net 3.5 :o) – Sir Rufo Oct 21 '16 at 23:04