Felület frissítése WinForms
2020-03-08T16:56:17+01:00
2020-03-10T20:46:09+01:00
2022-08-11T18:40:30+02:00
yguernen
Sziasztok!
Hosszú ideje keresem a megoldást a következő problémára - beleértve a prog.hu témáit is -, de sehogyan sem sikerül megérteni a lényeget és megtalálni a megoldást.

using System; using System.Diagnostics; using System.Threading.Tasks; using System.Windows.Forms; namespace Folyamatjelzo { public partial class Form1 : Form { public Form1() { InitializeComponent(); } public void Kiir(int s) { label1.Text = s.ToString(); } private void button1_Click(object sender, EventArgs e) { Szamolo.Start(); } } public static class Szamolo { public static async void Start() { await Task.Run(() => { for (double i = 0; i <= 20000; i++) { if (i % 10 == 0) Debug.Print(i.ToString()); } }); } } }
Ebben a kódrészletben szeretném megoldani, hogy a label1 értéke frissüljön mindig, amikor az i értéke osztható tízzel. Arra találtam megoldást, hogy a kezelőfelület ne "fagyjon meg", de a label1 értékének beállítása nem megy.

Kérem szíves segítségeteket és hozzá egy kis magyarázatot is.
Mutasd a teljes hozzászólást!
H,

using System.Threading.Tasks; using System.Windows.Forms; namespace Folyamatjelzo { public partial class Form1 : Form { public Form1() { InitializeComponent(); } public void Kiir(int s) { label1.Text = s.ToString(); } private void button1_Click(object sender, EventArgs e) { Szamolo.Start(this); } } public static class Szamolo { public static async void Start(From1 form) { await Task.Run(() => { for (double i = 0; i <= 20000; i++) { if (i % 10 == 0) { Debug.Print(i.ToString()); form.label1.Invoke(
(MethodInvoker)(() => label1.Text = string.Format("{0}",i)) } } }); } } }
*szerk Az indentálás meglehetősen használhatatlan eme editorban, így kérlek ellenőrizd a zárójeleket!

B
Mutasd a teljes hozzászólást!

  • private void button1_Click(object sender, EventArgs e) { Szamolo.Start(); this.Refresh(); }
    Ha jól emlékszem, akkor a Refresh() függvénnyel lehet a teljes form-ot frissíteni.
    Mutasd a teljes hozzászólást!
  • H,

    using System.Threading.Tasks; using System.Windows.Forms; namespace Folyamatjelzo { public partial class Form1 : Form { public Form1() { InitializeComponent(); } public void Kiir(int s) { label1.Text = s.ToString(); } private void button1_Click(object sender, EventArgs e) { Szamolo.Start(this); } } public static class Szamolo { public static async void Start(From1 form) { await Task.Run(() => { for (double i = 0; i <= 20000; i++) { if (i % 10 == 0) { Debug.Print(i.ToString()); form.label1.Invoke(
    (MethodInvoker)(() => label1.Text = string.Format("{0}",i)) } } }); } } }
    *szerk Az indentálás meglehetősen használhatatlan eme editorban, így kérlek ellenőrizd a zárójeleket!

    B
    Mutasd a teljes hozzászólást!
  • Köszönöm!
    Működik.
    Kérlek, magyarázd el néhány mondatban az 'INVOKE' és a 'MethodInvoker' jelentését és működését.
    Mutasd a teljes hozzászólást!
  • Szia,

    A Control.Invoke végrehajt egy "delegátumot" azon a szálon, mely birtokolja a Controlt.
    A Methodinvoker a "delegátum formája", melyet végrehajt a fenti metódus.

    Control.Invoke Method (System.Windows.Forms)

    MethodInvoker Delegate (System.Windows.Forms)

    még ez jó lehet neked
    Delegátumok C#-ban Krizsán Zoltán iit - PDF Free Download

    B
    Mutasd a teljes hozzászólást!
  • Nagyjából sikerült megemésztenem amit írtál és hivatkoztál.
    Ezt a példakódot készítettem az említettek alapján. Megj.: Az ExcelExportDataTable.XlsExport osztály régebbi saját termék. Feladata, hogy a paraméterek alapján hozzáférjen a megadott excel fájl kiválasztott munkalapjához, és tartalmát DataTable típusként adja vissza propertyn keresztül. A példa a téma címétől eltérően WPF alapú.

    namespace XlsFeldolgWPF { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void bt_Start_Click(object sender, RoutedEventArgs e) { DataTable eredmeny=null; Thread thread = new Thread(() => { eredmeny = XlsFeldolg.Kezdes(); Dispatcher.Invoke(() => { dg_Table.ItemsSource = eredmeny.DefaultView; lb_Cimke.Content = "Kész!"; pb_Jelzo.IsIndeterminate = false; }); }); pb_Jelzo.IsIndeterminate = true; thread.Start(); lb_Cimke.Content = "Betöltés..."; } } public static class XlsFeldolg { public static DataTable Kezdes() { ExcelExportDataTable.XlsExport xlsExport = new ExcelExportDataTable.XlsExport(); xlsExport.MunkalapExport(@"z:\MegosztottVM\gtdxls.xlsx", "Munka1", 2, 100, false); return xlsExport.XlsMunkalapok; } } }
    Ha jól értem, itt az történik, hogy a MainWindow bt_Start_Click eseménye az XlsFeldolg osztály Kezdes nevű metódusát (ami az ExcelExportDataTable egy példányát használja) másik szálon indítja, mint amin a GUI fut, ezért nem "fagy meg" a kezelőfelület. Történik mindez a thread.Start() hatására. Majd amikor a Kezdes metódus befejeződik és visszatér, akkor ez a másik szál a Dispatcheren keresztül fér hozzá a GUI szálához (mert máshogy nem lehet hozzáférni). A Dispatcher Invoke metódusa a benne foglalt névtelen metóduson keresztül adja át a DataGridnek a DataTable típus aktuális értékét, állítja át a Label Content tulajdonságát, és állítja meg a folyamatjelzőt.

    Jól gondolom?
    Megállítani hogyan lehet a másik szálat, ha például lenne egy mégse gomb? A thread.Abort() lenne a megoldás?
    Mutasd a teljes hozzászólást!
  • Szia,
    igen, amit mondasz az járható út.
    A helyedben átgondolnám a BackgroundWorker használatát, mivel az pontosan ilyen dolgokra van kitalálva. A Thread-et inkább számításigényes feladatokban használnám, mivel nehézkes vele "információt szerezni" a másik szálról.
    A BackgroundWorker tipikusan arra való, hogy a háttérben futó thread "kommunikáni" tud a GUI threaddel.

    B
    Mutasd a teljes hozzászólást!
  • Olvastam arról is itt. Nekem az jött át, hogy Async Await, mint a C# "újdonsága" leegyszerűsíti az aszinkron hívásokat. A témaindító hozzászólásban erre hoztam egy példát. Viszont sok minden nem tiszta vele kapcsolatban. Ahogy te is írtad, a winforms megoldás esetében működik, és meg is értettem a lényeget. De mi a helyzet akkor, amikor olyan metódust szeretnék hívni, ami az utolsó példámban szerepel, tehát ami hosszan dolgozik pl. az excel fájl megnyitásán és kiovasásán, majd valamilyen értékkel tér vissza. A leírások alapján a Task<T> lenne a megoldás, de az exceles datatable programban sehogy sem sikerült async await módszerrel megoldani. A Threades megoldást most azért választottam, mert úgy érzem, hogy ezzel közelebb kerültem a megértéshez.
    Abban még segítenél, hogy az utolsó, exceles WPF programban az async-es (vagy akár az általad említett BackgroundWorkeres) módszert hogyan tudnál alkalmazni?
    Mutasd a teljes hozzászólást!
  • Persze, csatolva megleled.
    Egyszerűen csinál valamit és közben frissíti a GUI-t. Ez a lényege a BackgroundWorker-nek.

    B
    Mutasd a teljes hozzászólást!
    Csatolt állomány
  • Köszönöm! Sokat segítettél!
    Mutasd a teljes hozzászólást!
Tetszett amit olvastál? Szeretnél a jövőben is értesülni a hasonló érdekességekről?
abcd