Zakładki TabControl jako osobne wątki

0

Witam,

Piszę sobie prostą aplikacje składająca się z TabControl, a jako zakładki są moje klasy dziedziczące po TabPage + parę dodatkowych kontrolek na nich, min buttonStart i dataGridView. Jest tam tez funkcja getData() która
zwraca DataTable do wyświetlenia w dgv. Problem polega na tym, że te zakładki mają być osobnymi wątkami, tak, aby długie wykonywanie funkcji getData() nie "wieszało" całej aplikacji, tylko aby można było spokojnie działać dalej. I teraz pytanie, co tak naprawdę powinno być osobnym wątkiem, próbowałem w innym wątku wykonać samą metodę getData(), ale to nie przynosi rezultatu. Być może powinno być to robione już w tym momencie:

tabControl.Controls.Add(new MyTabPage("tytul"));

tylko nie bardzo wiem jak do tego podejść, no i czy to będzie ok.

Proszę więc o jakieś rady przede wszystkim jeśli chodzi o podejście do tematu...
Ale oczywiście jeśli ktoś zna/posiada jakieś przykłady chętnie podejrzę.

0

Wydaje mi się, że najlepiej będzie jak sama metoda getData będzie działać asynchronicznie nie blokując gui. I co to niby znaczy, że każdy TabPage ma byc osobnym wątkiem? Wykonujesz pewne operacje w tle używając kontrolek rozmieszczonych w oknie. A czy będą one umieszczone na TabPage czy bezpośrednio w oknie to akurat nie ma znaczenia

0

bylo juz wiele razy na tym forum
dlugo trwajaca operacje uruchamiasz asynchronicznie
uzyc delegata i callback

0

Zrobiłem taki przykład:

public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            Closing += new CancelEventHandler(Form1_Closing);
        }

        void Form1_Closing(object sender, CancelEventArgs e)
        {
            if (thread != null && thread.IsAlive) thread.Abort();
        }

        private void buttonStart_Click(object sender, EventArgs e)
        {
            cls = new TClass("temp text", 10);
            thread = new Thread(new ParameterizedThreadStart(metoda_wywolywana_watkiem));
            act_delegat = new my_delegate(metoda_dodajaca_wpisy_do_dgv);
            thread.Start(cls);
        }

        void metoda_dodajaca_wpisy_do_dgv(TClass c)
        {
            string[] temp = c.proc();
            foreach(string str in temp)
                dataGridView.Rows.Add(new object[] { dataGridView.Rows.Count, str });
        }

        void metoda_wywolywana_watkiem(object ob)
        {
            this.Invoke(act_delegat, ob);
        }

        Thread thread;
        TClass cls;
        delegate void my_delegate(TClass obj);
        my_delegate act_delegat;
    }

    public class TClass
    {
        private string text;
        private int lines;

        public TClass(string txt, int n)
        {
            text = txt;
            lines = n;
        }

        public string[] proc()
        {
            for (int i = 0; i < 1000000;i++ )
            {
                for (int k = 0; k < 1000000; k++) ;
            }
            string[] temp = new string[lines];
            for (int i = 0; i < lines; i++)
                temp[i] = text + " " + (i + 1);
            return temp;
        }
    }

Metoda public string[] proc() ma wykonać długotrwałe obliczenia (tutaj po prostu liczenie),
jednak po kliknięciu buttona aplikacja nie odpowiada do czasu zakończenia obliczeń...
Co jeszcze jest nie tak?

0

No i po długiej walce udało mi się znaleźć działające rozwiązanie, kod wklejam, bo może znajdzie się ktoś komu się przyda...

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            Closing += new CancelEventHandler(Form1_Closing);    
        }

        void Form1_Closing(object sender, CancelEventArgs e)
        {
            if (thread != null && thread.IsAlive) thread.Abort();
        }

        private void buttonStart_Click(object sender, EventArgs e)
        {
            act_delegate = new ResultDelegate(metoda_wywolana_z_watku);
            cls = new TClass("text", 10, new ResultDelegate(resultcallback));
            thread = new Thread(new ThreadStart(cls.proc));
            thread.Start();
        }

        void metoda_wywolana_z_watku(Array txt)
        {
            for (int i = 0; i < txt.Length; i++)
                dataGridView.Rows.Add(new object[] { dataGridView.Rows.Count, txt.GetValue(i).ToString() });
        }

        void resultcallback(Array txt)
        {
            this.Invoke(act_delegate, txt);
        }

        Thread thread;
        TClass cls;
        ResultDelegate act_delegate;
    }

    public class TClass
    {
        private string text;
        private int lines;
        private ResultDelegate callback;

        public TClass(string txt, int n, ResultDelegate del)
        {
            text = txt;
            lines = n;
            callback = del;
        }

        public void proc()
        {
            Thread.Sleep(10000);
            string[] temp = new string[lines];
            for (int i = 0; i < lines; i++)
                temp[i] = "text dodawany z watku: " + text + " linia " + (i + 1);
            callback(temp);
        }
    }

    public delegate void ResultDelegate(Array txt);
0

mozna prosciej, np.

masz jakis delegat (np. mozesz uzyc jakis standardowych MethodInvoker, Func<TResult, ...>)
to odpalasz BieginInvoke
wczesniej musisz stworzyc 2 metody, pierwsza przeprowadzajace obliczenia i kolejna funkcja callback, czyli zostanie wywolana, kiedy pierwsza funkcja sie zakonczy

MethodInvoker mi = MethodStart;
mi.BeginInvoke(MethodDone, mi);

void MethodStart()
{ cos sobie robie, w osobnym watku }

void MethodDone(IAsyncResult ar)
{
  ((MethodInvoker)ar.AsyncState).EndInvoke(ar);
  mam wyniki, cos moge z nimi zrobic, dalej jestem w osobnym watku
  wiec kontrolki modyfikuje uzywajac InvokeRequired i Invoke
}
0

Czy mógłbyś Twoją wersję umieścić jakoś w kontekście mojego schematu programu,
chodzi mi o to co w jakim miejscu ma być zdefiniowane itd....
Co w klasie "roboczej" a co w klasie GUI?

0

w gui powinno byc stworzenie i odpalenie delegata (BeginInvoke)
metoda robocza moze (a moze nawet powinna) byc umieszczona w klasie roboczej, szczegolnie jesli te obliczenia uzywaja jakis wielu dodatkowych zmiennych, jesli jest to tylko np. wywoalnie jakiegos serwisu, czy zapytanie do bazy, to nie musisz szalec i jesli to umiesciesz w gui tez bedzie ok
metoda callback powinna byc w tym samym miejscu co wywolanie na delegacie, czyli w naszym przypadku w gui, tym bardziej jest to poprawne podejscie, jesli w tym momencie powinno nastapic zmowyfikowanie pewnych wartosci na gui
sama definicja delegata moze byc w klasie roboczej lub jesli jej jednak nie masz to w gui, mozesz tez uzyc juz jakiegos zdefiniowanego delegata w frameworku, jesli ci odpowiada jego definicja

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