Home > OS >  How can I stop the Task.Run()?
How can I stop the Task.Run()?

Time:09-16

I'm newer to the concept of threading and I would like to use Task that is a component of Thread in my application because the save task takes time for executing.

This is my code:

    private void SaveItem(object sender, RoutedEventArgs e)
    {
        // Button Save Click ( Save to the database )

        Task.Run(() =>
        {
            var itemsS = GridviewServices.Items;

            Dispatcher.Invoke(() =>
            {
                foreach (ItemsModel item in itemsS)
                {
                    PleaseWaittxt.Visibility = Visibility.Visible;

                    bool testAdd = new Controller().AddItem(item);
                    if (testAdd)
                        Console.WriteLine("Add true to Items ");
                    else
                    {
                        MessageBox.Show("Add failed");
                        return;
                    }
                }
                PleaseWaittxt.Visibility = Visibility.Hidden;
            });
        });

        MessageBox.Show("Save Done"); 

        // update the gridView
        var results = new Controller().GetAllItems();
        Gridview.ItemsSource = null;
        Gridview.ItemsSource = results;
        Gridview.Items.Refresh();
    }

The problem is that when I save all items, I got duplicate data in the database. Otherwise, the count of ItemsS is fixed to 300, but after the saving, I got 600,

Did Task.Run() repeat the save task to the database ?

NB: I'm working on UI project ( WPF Desktop app )

CodePudding user response:

I'm thinking you'd need something along the lines of this. I quickly whipped it up but i hope its enough to attempt a fix yourself.

private async void SaveItem(object sender, RoutedEventArgs e)
{
  try {
    var itemsS = GridviewServices.Items.ToList(); // to list makes shallow copy

    await Task.Run(() => {
          foreach (ItemsModel item in itemsS)
          {
              bool testAdd = new Controller().AddItem(item);
          } 
      });

    // Dont update ui in task.run, because only the ui thread may access UI items
    // Do so here - after the await. (or use dispatcher.invoke).

   GridviewServices.Items.Clear(); 
   GridviewServices.Items = itemsS;
 
  } catch { ... } // Handle exceptions, log them or something. Dont throw in async void!
 
}

I'm also thinking this would work:

  private async void SaveItem(object sender, RoutedEventArgs e)
    {
        // Button Save Click ( Save to the database )

        var itemsS = GridviewServices.Items;
        await Task.Run(() =>
        {
                foreach (ItemsModel item in itemsS)
                {
                    Dispatcher.Invoke(() => {PleaseWaittxt.Visibility = Visibility.Visible;})

                    bool testAdd = new Controller().AddItem(item);
                    if (testAdd)
                        Console.WriteLine("Add true to Items ");
                    else
                    {
                        MessageBox.Show("Add failed");
                        return;
                    }
              
                }
                Dispatcher.Invoke(() => {PleaseWaittxt.Visibility = Visibility.Hidden;})
        });

        MessageBox.Show("Save Done"); 

        // update the gridView
        var results = new Controller().GetAllItems();
        Gridview.ItemsSource = null;
        Gridview.ItemsSource = results;
        Gridview.Items.Refresh();

    }

CodePudding user response:

The problem you're running in to, is because the Task you're executing isn't running in parallel, but synchronously to the rest of your application.

When you're running CPU-intensive tasks in the background of your UI-application, you'll want to either work with actual threads or async/await - which is what you attempted with your code.

What you'll want to do is something similar to this:

private async void SaveItem(object sender, RoutedEventArgs e) => await Task.Run(
/*optionally make this async too*/() => {
    // Execute your CPU-intensive task here
    Dispatcher.Invoke(() => {
        // Handle your UI updates here
    });
});

This is just a general overview, I don't know your exact use-case, but this should get you started in the right direction.

One thing to be weary of when using Lambdas and such, is closures. If your application tends to use a lot of memory, you might want to re-think the structure of your calltree and minimize closures in your running application.

  • Related