0

I know there are several question related to my issues, I've studied them all but it seems that I still can't get it. Something like this or like this.

I have a method that downloads some files through FTP (it takes somewhere around 5 seconds). When I click the button to download the files I also want to change a control property so that a "loading" kind of thing is visible.

For this I have a CircleProgressBar with "animated" property set by default to false. When I call the previous method I want first to change that property to true and after the download is complete to set it back to false as it was.

I tried many solutions but in vain:

void UpdateMessage(bool value)
    {
        Action action = () => DownloadLC_Normal_CircleProgressBar.animated = value;
        Invoke(action);
    }
    private void DownloadLC_Normal_Button_Click(object sender, EventArgs e)
    {
        // try 1
        //UpdateMessage(true);

        // try 2
        //DownloadLC_Normal_CircleProgressBar.Invoke((MethodInvoker)(() =>
        //{
        //    DownloadLC_Normal_CircleProgressBar.animated = true;
        //}));

        // try 3
        if (DownloadLC_Normal_CircleProgressBar.InvokeRequired)
        {
            DownloadLC_Normal_CircleProgressBar.BeginInvoke((MethodInvoker)delegate () { DownloadLC_Normal_CircleProgressBar.animated = true; });
        }
        else
        {
            DownloadLC_Normal_CircleProgressBar.animated = false;
        }

        // DOWNLOAD FILES THROUGH FTP BY CALLING A METHOD FROM A .cs FILE 
        // FROM THE PROJECT

        //UpdateMessage(false);
        //DownloadLC_Normal_CircleProgressBar.animated = false;
    }

The CircleProgressBar never animates. What am I missing? What am I doing wrong, please? :(

EDIT: My missing part of code:

ftp ftpClient = new ftp("ftp://" + "192.168.1.200" + "/", "anonymous", "anonymous");
NetworkCredential credentials = new NetworkCredential("anonymous", "anonymous");
string url = "ftp://" + "192.168.1.200" + "/Documents and Settings/";
ftpClient.DownloadFtpDirectory(url, credentials, newDirectoryDownloadLocation);
Marko
  • 407
  • 1
  • 7
  • 19
  • Where are your Download method? Please, post it.I believe you are making a synchronous call, which will lock the UI thread for download, so, there is no UI update till your download finishes. – Vinicius Gonçalves Nov 08 '17 at 12:49
  • 2
    Not sure this is a threading issue. More like a logic issue. It looks to me as though your DownloadLC_Normal_Button_Click is called from a UI event - when a button is clicked, right? In that case DownloadLC_Normal_CircleProgressBar.InvokeRequired will return false which means the only line that ever gets executed is DownloadLC_Normal_CircleProgressBar.animated = false; Could I suggest you put breakpoints on the 2 lines in your // try 3 section and confirm what actually gets executed. Hope this helps. AB – Adam Benson Nov 08 '17 at 12:53
  • Now I saw this line, could be it too: else { DownloadLC_Normal_CircleProgressBar.animated = false; It should be DownloadLC_Normal_CircleProgressBar.animated = true instead. – Vinicius Gonçalves Nov 08 '17 at 12:55
  • Like I said, it looks like this call is made synchronously. – Vinicius Gonçalves Nov 08 '17 at 12:56
  • @ViniciusGonçalves I've put true on else without any results. So you say that if it is synchronously executed I'll have to wait till it's finished before making any other changes. – Marko Nov 08 '17 at 13:02
  • @Marko, please, see my answer. Post the result please. – Vinicius Gonçalves Nov 08 '17 at 13:07

2 Answers2

2

One of the easiest options is to use async/await:

async void DownloadLC_Normal_Button_Click(object sender, EventArgs e)
{
    DownloadLC_Normal_CircleProgressBar.animated = true;
    DownloadLC_Normal_Button.Enabled = false; // prevent further clicks
    await Task.Run(() =>
    {
        ...  // long running code, use `Invoke` to update UI controls
    });
    DownloadLC_Normal_CircleProgressBar.animated = false;
    DownloadLC_Normal_Button.Enabled = true;
}
Sinatr
  • 20,892
  • 15
  • 90
  • 319
  • I've tested your approach and it works, indeed, although the background and the colors get messed up because of the DownloadLC_Normal_Button.Enabled = false; thing. Could you explain it a little to me please or post some references for the logic behind it? – Marko Nov 08 '17 at 13:08
  • Since you know the words you can look for it yourself ;) Not sure if [this](https://learn.microsoft.com/en-us/dotnet/csharp/async) or [this](https://msdn.microsoft.com/library/hh191443(vs.110).aspx) msdn explanation is better. You can use a flag to prevent another task from being created, while previous one isn't finished. If you really want to block UI for a duration (not really recommended), then a simple workaround is to call `Application.DoEvents()` after synchronous update UI. – Sinatr Nov 08 '17 at 13:15
  • This was my initial approach, to get the job done out of the queue with App.DoEvents(). So: change the control property, App.DoEvents(), then the FTP download, then change the UI back. It didn't worked, I don't know why. – Marko Nov 08 '17 at 13:26
  • I appreciate your intervention, Sinatr! I will mark Vinicius's answer as the right one, even if yours is as correct as his, but he came first with the idea and the comments. Please don't mind. Thank you very much! :) – Marko Nov 08 '17 at 13:33
2

I'm assuming you're using framework 4.5/higher or 4.0 with Microsoft.Bcl.Async installed ok.

Try it:

private async void DownloadLC_Normal_Button_Click(object sender, EventArgs e)
{
    try
    {
        DownloadLC_Normal_Button.Enabled = false;
        DownloadLC_Normal_CircleProgressBar.animated = true;

        ftp ftpClient = new ftp("ftp://" + "192.168.1.200" + "/", "anonymous", "anonymous");
        NetworkCredential credentials = new NetworkCredential("anonymous", "anonymous");
        string url = "ftp://" + "192.168.1.200" + "/Documents and Settings/";

        //the code you post + change this line from:

        //ftpClient.DownloadFtpDirectory(url, credentials, newDirectoryDownloadLocation);

        //to: It makes the call be async

        await Task.Run(() => ftpClient.DownloadFtpDirectory(url, credentials, newDirectoryDownloadLocation));
    }
    finally
    {
        DownloadLC_Normal_CircleProgressBar.animated = false;
        DownloadLC_Normal_Button.Enabled = true;
    }
}
Vinicius Gonçalves
  • 2,514
  • 1
  • 29
  • 54
  • 2
    Yes, I do use 4.5 and it works. As I said to Sinatr also, the DownloadLC_Normal_Button.Enabled = false; ruins the background, frames and colours while the method is executed (4-5 seconds). But it does the job. Thank you, Vinicius! – Marko Nov 08 '17 at 13:24
  • You're welcome! Mark as anwer if worked for you! Tks – Vinicius Gonçalves Nov 08 '17 at 13:28