Odwołanie do obiektu i inne zagadnienia wielowatkowe

0

Przy ostatnim delegacie wywala mi często błąd System.NullReferenceException - Odwołanie do obiektu nie zostało ustawione na wystąpienie obiektu. Ktoś coś zaradzi?

private void button1_Click(object sender, EventArgs e)
        {

            watek1[licznik] = new Thread(wykonajWatek1);
            watek1[licznik].Start();
            licznik++; 
        }
        
        private void wykonajWatek1()
        {
            this.Invoke((MethodInvoker)delegate
            {
                kolejka[licznik] = new PictureBox();
                kolejka[licznik].Location = new Point(325, n - 150);
                kolejka[licznik].Image = wielowatkowa.Properties.Resources.car;
                kolejka[licznik].Size = new Size(20, 37);
                this.Controls.Add(kolejka[licznik]);
            });


            for (int i = 0; i < 500; i++)
            {
                this.Invoke((MethodInvoker)delegate
                {
                    kolejka[licznik].Location = new Point(kolejka[licznik].Location.X, kolejka[licznik].Location.Y - 3);
                    this.Refresh();
                });
                Thread.Sleep(50);
            }
        } 
0

Radzę podejrzeć wartości zmiennych, kiedy wyjątek występuje.

0
  1. Nie uruchamiałem, ale podejrzewam, że masz race condition na zmiennej licznik,
  2. Kilka razy wciśnięty button uruchamia tyle samo wątków w Twoim kodzie, musisz zabezpieczać.
0

Wyobraź sobie, że jeden wątek właśnie wykonuje pętlę for, a w tym czasie udało ci się nacisnąć przycisk. Licznik zostaje zwiększony, ale zanim wykona się linia new PictureBox drugi wątek wznawia wykonywanie pętli. Masz wówczas sytuację, że kolejka[licznik] == null. Nie musisz generalnie sobie tego wyobrażać. Możesz użyć debuggera i sprawdzić w momencie rzucenia wyjątku jaki jest stan licznika i jakie są wartości w kolejka.

Tak się jednak zastanawaiam po co ci te wątki, skoro i tak wszystkie operacje wykonujesz w wątku UI? Bardziej sensowne byłoby wykorzystanie osobnej klasy do przedstawienia samochodu. W jednym osobnym wątku iterowałbyś po obiektach (nie kontrolkach) i zmieniałbyś ich pozycje, a następnie wywoływał Refresh raz. W zdarzeniu Paint natomiast aktualizowałbyś kontrolki na podstawie tych obiektów.

0

Ok zabezpieczenie wątku zrobiłem.

0

Możesz opisać co chcesz zrobić od A do Z to może lepiej będzie dało się to zrobić.

0

Ok z tamtymi już wiem w czym problem.

0

Wątek się kończy gdy wykona całe zadanie :). Natomiast jak użytkownik kliknie przycisk to zawsze są tworzone wątki, stare nie są zabijane.

0

Picturebox się zawiesza bo wszystkie wątki korzystają z tego samego pola licznik, jak tworzysz nowy wątek to inkrementujesz ten licznik, więc rusza się tylko nowy(bo teraz na niego wskazuje licznik).

0

Hmmm pamiętam jak przerabiałem aplikacje z WinForma na WPF ^^ mój poprzednik coś podobnego jak ty wymyślił. W sensie dodawanie kontrolek przycisków do panelu. Dodatkowo zrobił obok 15 list przechowujących parametry przycisku. Przerobiłem to w ten sposób

Więc stworzyłem sobie model przycisku przechowujących najważniejsze parametry

class ButtonCategory : Button
    {
        public int idCategory;                              // Id kategori która reperezentujemy
        public string categoryName;                         // Nazwa kategori reprezentowanej
        public int countCustomer;                           // Ilosc klientów w danej kategori przy odpowiednich parametrach kategori perezentowanej
        public int parametrKomornik;                        // Parametr komornik prezentowanej kategori   (parametr otrzymywany z API, nie jest on wykorzystywany nigdzie w aplikacji lecz stanowczo kazali nic nie ruszać oraz iż ma być on przechowywany)

        /// <summary>
        /// Tworzenie przycisku oraz przypisanie jej niezbędnych parametrów
        /// </summary>
        /// <param name="_categoryName">Nazwa</param>
        /// <param name="_countKlientow">Ilosc klientow</param>
        /// <param name="_idKategory">Id kategori</param>
        /// <param name="_parametrKomornik">parametr komornik</param>
        public ButtonCategory(string _categoryName, int _countKlientow, int _idKategory, int _parametrKomornik)
        {                                                                                            
            this.countCustomer = _countKlientow;         // przypisanie
            this.categoryName = _categoryName;           // przypisanie
            this.idCategory = _idKategory;               // przypisanie
            this.parametrKomornik = _parametrKomornik;   // przypisanie
            ConfigButton();                              // Ustawienie profilu przycisku
          
        }

        /// <summary>
        /// Funkcja zarządzająca wizualizacją przycisku
        /// </summary>
        private void ConfigButton()
        {
            
            Content = new TextBlock()                                          // Ustawienie textu na TextBlock dzieki czemu można mieć wiele linijek text w przycisku
            {
                FontSize = 11,                                                 // Ustawienie czcionki
                Text = categoryName + " ( " + countCustomer + " ) ",           // Ustawienie textu na nazwę prezentowanej kategori + "(ilość klientów)"
                TextAlignment = TextAlignment.Center,                          // Ustawienie wysrodkowania
                TextWrapping = TextWrapping.Wrap                               // Ustawienie wapingu

            }; 
            Width = 100;                                                      // Ustawienie szerokości przycisku
            Height = 50;                                                      // Ustawienie wysokości przycisku
            Margin = new Thickness(5, 5, 5, 5);                               // Ustawienie marginesu, żeby przyciski do siebie nie przylegały 
        }
    }

 

ConfigButton() - ustawia konfiguracje wyglądu przycisku.

Dodanie Przycisku do WrapPanel name="Wp_Button"

 
ButtonCategory CategoryButton = new ButtonCategory("wkładamy dane jakie mamy wrzucić"); // Stworzenie obiektu oraz jego konfiguracja
WP_Button.Children.Add(CategoryButton);  // Dodanie obiketu to WarpPanelu
amountCategory_dynamic = amountCategory_dynamic + 1; // A to mam do zliczania ilości przycisków przez co klasa zarządzająca wielkością okna oraz położeniem wie jak ma powiększyć okno

CategoryButton.Click += Click_StandardCategory; // Dołożenie akcji przycisku

Fragment odwołania się do obiektu i rozpoznanie co to za obiekt z jakimi parametrami

 
private void Click_StandardCategory(object sender, EventArgs e)
        {
ButtonCategory ChooseButton = (ButtonCategory)sender; // Da sprawdzenia jaka została wybrana kategoria, i teraz z obiektu ChooseButton jesteś wstanie wyciagnac informacje takie jak ustawiłeś w modelu 
}

Nie pamiętam czy w WinFormie jest WarpPanel ale jak tak to polecam. Bo on sam ustawia rozmieszczenie przycisków. Dzięki czemu jak rozciągasz okno to masz więcej przycisków w jednym rzędzie albo jak zwęzisz to masz więcej kolumn. Do tego możesz dodać suwaka i nawet przyjemnie to wygląda.

1
        ... {
            watek1[licznik] = new Thread(wykonajWatek1);
            watek1[licznik].Start(); // 1) tu wątek startuje
            licznik++; // 2) tu zwiększasz licznik
        }
 
        private void wykonajWatek1()
        {
            this.Invoke((MethodInvoker)delegate
            {
                kolejka[licznik] = new PictureBox(); // 3) tu (BTW dlaczego całość jest w Invoke?) i poniżej odwołujesz się do kolejka[licznik]
                kolejka[licznik].Location = new Point(325, n - 150);
                kolejka[licznik].Image = wielowatkowa.Properties.Resources.car;
                kolejka[licznik].Size = new Size(20, 37);
                this.Controls.Add(kolejka[licznik]);
            });
 

Co Twoim zdaniem zagwarantuje, że cały punkt 3. wykona się PRZED 2? Masz tu typowy hazard, a ilość kodu w 3. w stosunku do ilości kodu pomiędzy 1. a 2. sugeruje, że niemal zawsze wykona się 2 (licznik++) przed 3 (kolejka[licznik]). Moim zdaniem albo nie przemyślałeś swojego pomysłu, albo kompletnie nie rozumiesz, co robisz. Zacznij od jakiegoś dużo prostszego przypadku.

0

Gdzie umieścić licznik? Usiądź z kartką i rozrysuj sobie swój pomysł. Ja nie wiem co chcesz osiągnąć, a Ty tego nie podałeś. Widzę jakąś tablicową zmienną kolejka, kolejną watek1 ("1" do tablicy? WTF? A masz też watek2? Co taka nazwa powie Ci za pół roku?). Napisz co dokładnie chcesz uzyskać i jak się do tego zabrałeś, to coś pomyślimy.

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