0

I want to send a progress bar that is available on my form to a function to display the progress of the operation of that function and finally return true if everything is fine and return false if else The operation inside the SaveBadCustomerMustStayMasdoodExcelFile function is executed asynchronously so as not to interfere with the execution of other operations. When the program runs and the compiler calls the line _ProgressBar.Invoke((MethodInvoker)(() => {_ProgressBar.Value = Convert.ToInt32(i);})); Inside the badCustomers.SendToDB(progressBar_BadCustomers) function, there is no feedback and the program seems to be stuck in an infinite loop. But if the output of the SaveBadCustomerMustStayMasdoodExcelFile function is defined as void, everything works fine.

My code when the system hangs:

In Button:

private void btn_ChoiceBadCustomersFile_Click(object sender, EventArgs e)
{
    try
    {
        DialogResult dialogResult = MessageBox.Show("message", "title",
            MessageBoxButtons.YesNo);
        if ((dialogResult == DialogResult.Yes))
        {
            bool result = false;
            try
            {                        
                result = GetDataFromExcelFile.SaveBadCustomerMustStayMasdoodExcelFile(
                    progressBar_BadCustomers).Result;
            }
            catch
            {
                result = false;
            }
            if (result)
            {
                //code...
            }
        }
    }
    catch
    {
        //code...
    }
}

Code In GetDataFromExcelFile.SaveBadCustomerMustStayMasdoodExcelFile(...)

public static class GetDataFromExcelFile
{
    public async static Task<bool> SaveBadCustomerMustStayMasdoodExcelFile(
        DevComponents.DotNetBar.Controls.ProgressBarX progressBar_BadCustomers)
    {
        try
        {
            PoomaDbAppEntities DB10 = new PoomaDbAppEntities();
            IQueryable<tbl_BadCustomers> dt = null;
            MyExcelWorkSpace _excelApp = new MyExcelWorkSpace();
            MyExcelWorkSpace.badCustomers badCustomers = new MyExcelWorkSpace
                .badCustomers();
            string path = badCustomers.select();
            if (path != String.Empty)
            {
                if (badCustomers.Open(path))
                {
                    try
                    {
                        await Task.Run(() => { dt = badCustomers
                            .SendToDB(progressBar_BadCustomers); });
                        return true;
                    }
                    catch
                    {
                        return false;
                    }
                }
                else
                {
                    return false;
                }
            }
            else
            {
                return false;
            }
        }
        catch
        {
            return false;
        }
    }
}

And In badCustomers.SendToDB(...) :

public class badCustomers : ExcelFile, IStartWorkWithExcelFile<tbl_BadCustomers>
{
    //code
    public IQueryable<tbl_BadCustomers> SendToDB(DevComponents.DotNetBar
        .Controls.ProgressBarX _ProgressBar)
    {
            try
            {
                //code
                _ProgressBar.Invoke((MethodInvoker)(() => {
                    _ProgressBar.Value = Convert.ToInt32(i); }));
            }
            catch
            {
                //code
            }
        }
        IQueryable<tbl_BadCustomers> dt = DB10.tbl_BadCustomers.Select(i => i);
        return dt;
    }
}

If the SaveBadCustomerMustStayMasdoodExcelFile function is defined as below, the program works, but I need to know if an error has occurred or not.

public async static void SaveBadCustomerMustStayMasdoodExcelFile(
    DevComponents.DotNetBar.Controls.ProgressBarX progressBar_BadCustomers)
{
    //code
}

If the SaveBadCustomerMustStayMasdoodExcelFile function is defined as below, the program works, but I need to know if an error has occurred or not.

public async static void SaveBadCustomerMustStayMasdoodExcelFile(
    DevComponents.DotNetBar.Controls.ProgressBarX progressBar_BadCustomers)
{
    //code
}
Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104
ferihfs
  • 3
  • 2
  • Usually, you pass a `IProgress` to the async method. The caller can easily wire this up to a progress bar using the `Progress` class. You will find some examples also on StackOverflow, e.g. https://stackoverflow.com/questions/68652535/using-iprogress-when-reporting-progress-for-async-await-code-vs-progress-bar-con – Klaus Gütter Jan 24 '23 at 14:22
  • 2
    `result= GetDataFromExcelFile.SaveBadCustomerMustStayMasdoodExcelFile(progressBar_BadCustomers).Result;` - lookin' for trouble, hah ;D - Fun aside: If it's async, await it. – Fildor Jan 24 '23 at 14:30
  • Usually when reporting progress there is a loop somewhere that does the reporting, I cannot see any such loop in the example. But it *does* report using an `i`, and that makes me worried about the overall design. But you should most likely use `Progress` or something equivalent. – JonasH Jan 24 '23 at 14:42
  • Take the IProgress reporting procedure from, e.g, [here](https://stackoverflow.com/a/74554087/7444103), it's also meant to update a ProgressBar -- In this platform, never (ever) use `.Wait()` or the `.Result` of Tasks you don't await – Jimi Jan 24 '23 at 14:51

1 Answers1

1

there is no feedback and the program seems to be stuck in an infinite loop.

This is because the code is using Result; full details on my blog.

To solve this, you want to avoid async void (i.e., for SaveBadCustomerMustStayMasdoodExcelFile); async void is intended for event handlers, so you can make btn_ChoiceBadCustomersFile_Click an async void method. Everything else should use await and async Task.

As far as the Progress goes, I echo the recommendations in the comments: IProgress<T> with Progress<T> makes your code cleaner (e.g., no Invoke necessary).

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810