(C#.NET) - Drobny problem z aktualizacją labeli i progressbar na żywo

Już Ci pokazuję kod. Ogólnie na początku dodałem private CancellationTokenSource cts;

Klasa, której to dotyczy:

  public void Timer1_Tick(object sender, EventArgs e)
        {
            progressBar1.Increment(20);

            if (progressBar1.Value == 100)
            {
                timer1.Stop();
                System.Threading.Thread.Sleep(101);
                cts = new CancellationTokenSource();
                CancellationToken token = cts.Token;
                Task.Factory.StartNew(() =>
                {
                    token.ThrowIfCancellationRequested();
                    foreach (var obj in listBox1.Items)
                    {
                        string dir = Convert.ToString(obj);
                        listBox3.DataSource = GetFileList("*.*", dir).ToArray();
                        int count = listBox3.Items.Count;
                        for (int i = 0; i < count; i++)
                        {
                            listBox5.Items.Add(listBox3.Items[i].ToString());
                        }
                    }
                    string filecount = Convert.ToString(listBox5.Items.Count);
                    textBox1.Text = filecount;
                    ExecuteSecure(() => label2.Text = "Przeszukano: 0 z " + filecount);


                    ExecuteSecure(() => label5.Visible = false);
                    ExecuteSecure(() => timer4.Start());
                    ExecuteSecure(() => progressBar1.Value = 0);
                    foreach (var file in listBox5.Items)
                    {
                        string obj = Convert.ToString(file);
                        try
                        {
                            ExecuteSecure(() => label4.Text = obj);
                            if (File.Exists(obj))
                            {
                                try
                                {
                                    using (FileStream scan_obj = new FileStream(obj, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                                    {
                                        //  System.Threading.Thread.Sleep(23);
                                        if (listBox2.Items.Contains(CheckObject(obj)))
                                        {
                                            ExecuteSecure(() => listBox4.Items.Add(obj));
                                            string foundcount = Convert.ToString(listBox4.Items.Count);
                                            ExecuteSecure(() => textBox3.Text = foundcount);
                                            ExecuteSecure(() => label3.Text = "Liczba znalezionych: " + foundcount);


                                        }
                                    }
                                }
                                catch
                                {

                                }
                            }
                        }
                        catch
                        {

                        }

                        string filecount2 = Convert.ToString(listBox5.Items.Count);
                        int scnnr = Convert.ToInt32(textBox2.Text);
                        scnnr = scnnr * 1 + 1 * 1;
                        ExecuteSecure(() => textBox2.Text = Convert.ToString(scnnr));
                        ExecuteSecure(() => label2.Text = "Przeszukano: " + scnnr + " z " + filecount2);
                        int step = Convert.ToInt32(textBox2.Text);
                        int final = Convert.ToInt32(textBox1.Text);
                        int precent = 0;
                        precent = (step * 100) / (final * 1);
                        ExecuteSecure(() => textBox4.Text = Convert.ToString(precent));
                        ExecuteSecure(() => progressBar1.Value = precent);
                        ExecuteSecure(() => CheckShieldLauncher.Properties.Settings.Default.ScanProgress = Convert.ToString(precent) + "%");
                    }
     
                }, token);
                  
            }
        }

Przycisk anulowania:

private void Button1_Click(object sender, EventArgs e)
        {
            cts.Cancel();
            CheckShieldLauncher.Properties.Settings.Default.ScanStatus = "Gotowe!";
            CheckShieldLauncher.Properties.Settings.Default.ScanProgress = "0%";
            if (textBox3.Text == "0")
            {
                MessageBox.Show("Przeszukanie przerwane! Nic nie znaleziono.");
                this.Close();
            }
            else
            {
                System.IO.StreamWriter FoundListGenerator = new System.IO.StreamWriter(Application.StartupPath + "\\Temp\\006.set");
                foreach (var obj in listBox4.Items)
                {
                    string obj_loc = Convert.ToString(obj);
                    FoundListGenerator.WriteLine(obj_loc.ToString());
                }
                FoundListGenerator.Close();
                CheckShieldFoundManager scan_result = new CheckShieldFoundManager();
                scan_result.Show();
                MessageBox.Show("Przeszukanie przerwane! Podczas skanowania zostały znalezione pożądane obiekty.");
                this.Close();
            }    

        }

Nie jestem pewien czy teraz głupoty nie piszę ale nie dało by rady wyrzucić timera i zamknąć to wszystko w pętli, której ticki określasz przez

System.Threading.Thread.Sleep(101);

I wtedy po naciśnięciu przycisku anulujesz pętlę ,masz większą kontrolę nad tym co się stanie bo pętla jeszcze dojdzie do końca. I wtedy się zatrzyma. Musiałbyś to wszystko zamknąć w coś w rodzaju

while( progressBar1.Value != 100 && kontynuacja)

Zmienna kontynuacja deklarujesz jako globalną i ustawiasz na true a w przycisku zmieniasz na false.
Ale nie znam do końca programu i nie mam czasu go analizować i dlatego nie wiem czy to rozwiązanie ma sens.

Kod dla przykładu napisany w minutę więc nie bierz go jako wzór a jedynie przykład jak to może działać

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

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        bool czy = true;
        private void ExecuteSecure(Action action)
        {
            if (InvokeRequired)
            {
                Invoke(new MethodInvoker(() => action()));
            }
            else
            {
                action();
            }
        }

        private void CountLabel()
        {
            Task.Factory.StartNew(() =>
            {
                for (int i = 0; i < 999999 && czy; i++)
                {
                    ExecuteSecure(() => label1.Text = "Processing " + i);
                    Thread.Sleep(1000);
                }
            });
        }

        public Form1()
        {
            InitializeComponent();
            CountLabel();
        }

        private void button1_Click(object sender, EventArgs e)
        {
           czy= false;
        }
    }
}

Teraz tak patrzę i przepraszam za to pomieszanie polskiego z angielskim :slight_smile:

Nie musiałem z timera rezygnować :smiley: Już tłumaczę jak to rozwiązałem! Dodałem stringa, od którego uzależniłem task. Task wyglądał tak, że jeśli string = A to rób formułę całą i tu ją wkleiłem, a gdy string = B to nie rób nic. Potem wystarczyło aby button zmieniał wartość tego stringa i poszło. :smiley: Dzięki wszystkim za pomoc! :smiley:

Jeśli sprawdzasz warunek, który może mieć tylko dwie wartości to używaj boolean. Jeśli więcej - własnego enuma.

Co do kodu, tak jak pisałem, zalecałbym użycie async/await. Do tego, w przypadku zwracania z innego wątku statusu/progresu, użyć eventów, nie będziesz mieć problemów z blokowaniem gui. Nie obraź się, ale ten kod to trochę druciarstwo. Do tego częste odwoływanie się do metody ExecuteSecure(…) może powodować chwilowe czkawki samej aplikacji.
Wrzuć gdzieś projekt na jakiś dropbox i podaj link, podpowiem co pozmieniać :).

To parę uwag co do twojego wpisu jest tu parę sensownych uwag jak z boolem czy tym ,że kod nie jest idealny ale to też początki a na początku najważniejsze by działało i autor wiedział czemu działa. Ale jest też parę zdań z którymi się nie zgodzę await jest używane więc nie wiem dlaczego tego nie widzisz. A odwoływanie się do tak prostej metody nie może spowodować czkawki aplikacji co więcej w większości projektów odwołuje się do większej liczby metod i to bardziej skomplikowanych. Tak naprawdę ta metoda to zabezpieczony Invoke.

Piszę z doświadczenia. Co do pełnego użycia TPL i async/await wg prawideł to niestety tutaj nie ma.