Invoke or BeginInvoke cannot be called on a control until th

0

Ludzie pomóżcie! Poniżej jest kod w którym wywala błąd taki jak w temacie. Za cholerę nie mogę zrozumieć o co biega. Żeby jeszcze udziwnić sprawę dodam, że jak usunę linijkę w której wywala błąd to wszystko działa cacy, czyli drugi progressbar zmienia swoje wartości.

widzę że ucięło mi tytuł, więc podaję pełną treść błędu : Invoke or BeginInvoke cannot be called on a control until the window handle has been created.

namespace watki_02
{
    public partial class Form1 : Form
    {
        public delegate void set_progressbar_callback(int wartosc);

        public Form1()
        {
            InitializeComponent();
            Thread watek_01 = new Thread(new ThreadStart(los_01));
            Thread watek_02 = new Thread(new ThreadStart(los_02));
            watek_01.Start();
            watek_02.Start();
            
        }
        /*********************************************/
        void los_01()
        {
            Random los = new Random();
            while (true)
            {
Tu wywala komunikat------>        progressBar1.Invoke(new set_progressbar_callback(set_progressbar_01), los.Next(0, 100));
                Thread.Sleep(100);
            }
        }
        /*******************************************/
        void los_02()
        {
            Random los = new Random();
            while (true)
            {
                Thread.Sleep(100);
                progressBar2.Invoke(new set_progressbar_callback(set_progressbar_02), los.Next(0, 100));
            }
        }
        /******************************************/
        void set_progressbar_01(int wartość)
        {
            progressBar1.Value = wartość;
        }
        /******************************************/
        void set_progressbar_02(int wartosc)
        {
            progressBar2.Value = wartosc;
        }
    }
}
0
rychu_elektryk napisał(a)

Ludzie pomóżcie! Poniżej jest kod w którym wywala błąd taki jak w temacie. Za cholerę nie mogę zrozumieć o co biega. Żeby jeszcze udziwnić sprawę dodam, że jak usunę linijkę w której wywala błąd to wszystko działa cacy, czyli drugi progressbar zmienia swoje wartości.

Funkcje robocze dla wątków różnią się nieznacznie, ale wystarczająco, by zachowanie było inne - zwróć uwagę, że dla drugiego progressbara w pętli najpierw wywoływany jest 100milisekundowy Sleep(). Jakie ma to znaczenie?

Otóż kiedy okno jest tworzone ale nie jest jeszcze widoczne, wtedy właściwość IsHandleCreated , od której stanu zależy czy można stosować Invoke'a, zwraca false - rezultatem jest ww. wyjątek.

Jak rozwiązać problem?

  1. przenieść w obu przypadkach Sleep jaką pierwszą linię do wykonania w pętli (niepoprawne do końca rozwiązanie, bowiem przy pewnych warunkach wyświetlenie formularza może zająć więcej niż 100ms).
  2. w konstruktorze przed odpaleniem wątków dodać linię:
    this.Visible = true;
    -3. (ku temu bym się skłaniał): korzystaj z Invoke tylko wtedy kiedy trzeba:
set_progressbar_callback cb = new set_progressbar_callback(set_progressbar_01);

while (true)
{
if (progressBar1.InvokeRequired)
    progressBar1.Invoke(cb, los.Next(0, 100));
else
    set_progressbar_01(los.Next(0,100));
    Thread.Sleep(100);
}

Powinno zadziałać nawet jeśli konstruktor "przyśnie" z wyświetleniem:

public Form1()
{
(...)
watek_01.Start();
watek_02.Start();

// set explicitly to false
this.Visible = false;
Debug.WriteLine(this.IsHandleCreated);

// sleep enough to make sure that threads loop executed several times
Thread.Sleep(2000);

this.Visible = true;
Debug.WriteLine(this.IsHandleCreated);
0

Wielkie dzięki za dogłębne wytłumaczenie. http://translator.telewizor.eu Naprawdę doceniam i pozdrawiam

1 użytkowników online, w tym zalogowanych: 0, gości: 1