TreeView feltöltése + List<> + LINQ lassú

TreeView feltöltése + List<> + LINQ lassú
2012-09-13T11:16:59+02:00
2012-09-14T12:26:35+02:00
2022-11-26T21:00:34+01:00
Wowbagger78
Sziasztok!

Van a következő enumom és structom.

public enum HatosagDataType : int { Hatosag = 1, Telepules = 2 } public struct Hatosag { public int ID; public int ParentID; public string Megnevezes; public HatosagDataType HatosagTipus; public string Szuro; }

List<Hatosag> tmpList = new List<Hatosag>();
-t feltöltöm adatbáziból. Ez rendben meg is történik rövid idő alatt.

Ezt a List-et felhasználva szeretnék feltölteni egy TreeView komponenst WinForms alatt. Látható, hogy az egyes szintek közötti kapcsolatot az ID és az arra mutató ParentID adja meg.

A feltöltést a következő kóddal végzem:

private void FillTreeViewByIntezmeny() { tvHatosag.BeginUpdate(); tvHatosag.Nodes.Clear(); List<Hatosag> HatosagLista = Data.GetHatosagTreeViewSource(Convert.ToInt32(cbIntezmeny.SelectedValue.ToString())); var KezdoHatosagLista = from g in HatosagLista where g.ParentID == 0 select g; LoadHatosagTreeViewNodes(KezdoHatosagLista, HatosagLista, null); tvHatosag.EndUpdate(); } private void LoadHatosagTreeViewNodes(IEnumerable<Hatosag> FilterHatosagLista, List<Hatosag> HatosagLista, TreeNode StartNode) { foreach (Hatosag hat in FilterHatosagLista) { if (hat.ParentID == 0) { //Gyökér TreeNode tn = new TreeNode(hat.Megnevezes); tn.ForeColor = Color.DarkBlue; tn.NodeFont = new Font(tvHatosag.Font, FontStyle.Bold); LoadHatosagTreeViewNodes(from g in HatosagLista where g.ParentID == hat.ID select g, HatosagLista, tn); tvHatosag.Nodes.Add(tn); } else { //Gyermek TreeNode tn = new TreeNode(hat.Megnevezes); tn.ForeColor = Color.DarkBlue; tn.NodeFont = new Font(tvHatosag.Font, FontStyle.Regular); LoadHatosagTreeViewNodes(from g in HatosagLista where g.ParentID == hat.ID select g, HatosagLista, tn); StartNode.Nodes.Add(tn); } }

A fenti kód tökéletesen működik, a TreeView-t feltölti, de mondjuk egy 18 ezres tételszámnál már várni kell 10-12 mp-t is mire megjelennek az adatok.

Elöször azt hittem, hogy a Node-ok TreeView-höz adása lassítja. Kikommenteztem tehát a Node-os részket és csak szimplán a rekurzív LINQ lekérdezések futottak, de ez sem segített. Így is maradt a lassúság (10-12 mp) mire végigfutott az összes rekurzív lekérdezés.

Hogyan tudnám ezt gyorsítani? Mit javasoltok?

Köszönöm a javaslatokat előre is.

W.
Mutasd a teljes hozzászólást!
Félek, hogy maga a TreeView lesz lassú ebben az esetben, de egyszerűen kipróbálhatod: futtatsd a kódod a TreeView manipuláló részek nélkül (de menjen végig az összes rekordon).

Próbáld ki WPF alatt, az nagyságrendekkel gyorsabban működik.

Alternatív javaslatként a dinamikus feltöltés marad, azaz, amikor a felhasználó megnyitja a Node-ot, akkor töltöd fel azt a megfelelő értékekkel, tehát nem rekurzívan, csak az épp látható részt - én hasonló problémánál így jártam el (NodeMouseDoubleClick esemény).
Mutasd a teljes hozzászólást!

  • Annyiban megerősíthetlek, hogy szerintem a LINQ gyorsasága megfelelő kell hogy legyen. Nekem a 65 ezer elemből álló listámat egy pillanat alatt töltötte fel egy DataGridView-ba. A KeyUp eseményre berakott filter is hasonlóképp gyors volt. Egy ekkora listával is el kellene boldogulnia. A program lényegét nem ismerem teljes részleteiben, de ha jól gondolom, akkor te egy szimpla adatbázist akarsz mutatni. Vannak benne gondolom rész-egész vagy inkább valamilyen strukturáltság (egy településen több hatóság is lehet,stb.).Erre valóban jó a TreeView control. Azonban azt nem értem, hogy miért kell rekurzívan ezt megvalósítani. Feltétlenül szükséges ez? Ugyanis a rekurzió veremműveletekkel jár. Nem lehetséges, hogy amiatt lassú a feltöltés?
    Mutasd a teljes hozzászólást!
  • Szia!

    Igen. Ez egy szimpla adatlekérő, adatmutató program amiben különféle szűrőszempontok szerint lehozza a releváns adatokat.

    Az adatbázis struktúrálva van és mint jeleztem, az adatok az adatbázisból nagyon gyorsan bekerülnek a List<T>-be csak onnan visszanyerni lassú.

    Hogyan szervezzem át a kódot, hogy felgyorsítsam a dolgot?

    Azonban azt nem értem, hogy miért kell rekurzívan ezt megvalósítani.
    => Én ezt a módját ismerem a listából való TreeView feltöltésnek:)

    Van esetleg alternatív javaslatod? A List<Hatosag>-ot megtartanám mivel célom, hogy a jövőben ASP.NET és WPF irányban is továbbfejlesszem a programot. Az adatok elérését/lekérdezését emiatt kiraktam egy Data Access Layer-be ami ilyen formában (List<Hatosag>) szolgáltatja ezt az adatot.

    W.
    Mutasd a teljes hozzászólást!
  • Félek, hogy maga a TreeView lesz lassú ebben az esetben, de egyszerűen kipróbálhatod: futtatsd a kódod a TreeView manipuláló részek nélkül (de menjen végig az összes rekordon).

    Próbáld ki WPF alatt, az nagyságrendekkel gyorsabban működik.

    Alternatív javaslatként a dinamikus feltöltés marad, azaz, amikor a felhasználó megnyitja a Node-ot, akkor töltöd fel azt a megfelelő értékekkel, tehát nem rekurzívan, csak az épp látható részt - én hasonló problémánál így jártam el (NodeMouseDoubleClick esemény).
    Mutasd a teljes hozzászólást!
  • Szia!

    Amit javasoltál azt megtettem és említettem is fentebb:

    Elöször azt hittem, hogy a Node-ok TreeView-höz adása lassítja. Kikommenteztem tehát a Node-os részket és csak szimplán a rekurzív LINQ lekérdezések futottak, de ez sem segített. Így is maradt a lassúság (10-12 mp) mire végigfutott az összes rekurzív lekérdezés.


    Tehát a TreeView nem befolyásolja a feltöltési sebességet szvsz.

    A dinamikus feltöltésre gondoltam már, de egyelőre ezt szeretném körbe járni és, ha más nincsen akkor jönne a dinamikus feltöltés. 3000-4000 tételre kultúrált sebességet produkál.

    W.
    Mutasd a teljes hozzászólást!
  • Kedves Wowbagger78!

    Nem tudom milyen alárendeltségi viszony van az adatbázisodban, de én arra gondolok, amit írtam is hogy van egy település és azon belül több hatóság. Gondolom lenne a fő node pointod a település és annak a gyermekei vagyis alárendeltjei lennének a hatóságok. Ha jól sejtem valahogy így nézne ki a treeview

    |
    -Bugac
    |
    -Pénzügyőrség
    -Rendőrség
    -Nyugdíjas fejvadász klub

    -Piripócs
    |
    -Bankrablók Pénzintézet
    -stb.

    Akkor ha a település osztályod tartalmazná a hatóságok listát ?
    Lenne egy listád a településekről.

    List<Telepules> telepulesek = new List<Telepules>();
    A telepulesek minden egyes eleme tartalmazna egy hatóság listát.
    List<Hatosag> HatosagLista = new List<Hatosag>();

    Ezekkel próbálod feltölteni a TreeView-t. De lehet hogy ez sem lesz gyorsabb mint a rekurzív megvalósítás.

    A TreeView-nak nincs DataSource property-je aminek csak úgy simán oda tudnád adni a listádat hogy töltse fel vele.

    Viszont a DataGridViewnak van DataSource-je. Valamint arra találtam olyan forrást, hogy lenyithatós lenne az egyes sorok. Csak hogy tudd ábrázolni az alárendeltséget.

    Collapse Expand DataGridView valami ilyesmire keress rá, most hirtelen nem találom.
    Mutasd a teljes hozzászólást!
  • Itt is a rekurziót javasolják:

    Populating a TreeView Control from a List

    W.
    Mutasd a teljes hozzászólást!
  • Megvan kiiratod ConsoleApplicationba. Mondjuk 18 ezer elem plusz a gyermekek párszor átfordítják a Consolet, de attól még ki van írva.

    Komolyra fordítva a szót. A TreeView lehet hogy nem a megfelelő control ehhez a művelet. Ha pl kiraknál egy ComboBox-ot, abból kiválasztanád az adott települést és akkor amelyik települést kiválasztottad, az ahhoz tartozó Hatóságokat sorolnád fel egy másik controlban ?
    Mutasd a teljes hozzászólást!
  • Ilyesmi amit említesz csak fordítva:)

    - NAV Közép-magyarországi Regionális Adó Főigazgatósága - NAV Észak-budapesti Adóigazgatási Ügyfélszolgálata - Budapest 01. ker. - Budapest 02. ker. - Budapest 03. ker. - Budapest 04. ker. - Budapest 05. ker. - Budapest 06. ker. - NAV Kelet-budapesti Adóigazgatósága 6,7,8,10,14,15,16,17 - NAV Közép-dunántúli Regionális Adó Főigazgatósága - NAV Ajkai Adóigazgatási Ügyfélszolgálata - Ábrahámhegy - Adásztevel - Adorjánháza

    Megfontolom amit javasolsz, de szvsz (hiszem!) az általam összerakott lista is alkalmas arra, hogy ebből kultúrált sebességgel listát tudjak gyártani, csak azt nem tudom még hogyan.

    Csapataink harcban állnak;)

    W.

    Mutasd a teljes hozzászólást!
  • Ilyen opció is lesz benne (Település alapján a hivatalok):)

    De a TreeView nem a lassító tényező mivel anélkül is lassú a List<Hatosag> végigjárása. Belátom, a rekurzió lehet a bűnös...

    W.
    Mutasd a teljes hozzászólást!
  • Én csak azért mondtam neked a rekurziót, mint lehetséges lassító tényezőt, mert mikor tanultunk róla, akkor a három tényező közül(idő, tárhely, érthetőség) közül csak az érthetőségre volt pozitív, de arra se mindig. Hanoi tornyánál például oké hogy 5 sor volt az egész probléma megoldása én mégsem tudtam megérteni.

    Azonban a másik két tényezőre negatívan hat. Verem műveletek vannak a háttérben. Emiatt nagyobb tárhelyre van szüksége és maguk a műveletek pedig időbe telnek. Aztán mivel neked az idő lenne fontos ennél a problémánál azért gondoltam, hogy esetleg ez a tulajdonsága játszhat közre.
    Mutasd a teljes hozzászólást!
  • Asszem megvan a megoldás bár ez sem az a villám. De az időt sikerült lehoznom 4-5 mp-re.

    Hierarchikusan oldottam meg a kérdést, a LINQ-t száműztem.

    A kód (csak ami változott):

    public struct Hatosag { public int ID; public int ParentID; public string Megnevezes; public HatosagDataType HatosagTipus; public string Szuro; public List<Hatosag> HatosagList; } private void LoadHatosagTreeViewNodes(List<Hatosag> HatosagLista, TreeNode StartNode) { foreach (Hatosag hat in HatosagLista) { TreeNode tn = new TreeNode(hat.Megnevezes); tn.ForeColor = Color.DarkBlue; tn.NodeFont = new Font(tvHatosag.Font, FontStyle.Bold); if (StartNode != null) StartNode.Nodes.Add(tn); if (hat.HatosagList != null) LoadHatosagTreeViewNodes(hat.HatosagList, tn); if (hat.ParentID == 0) tvHatosag.Nodes.Add(tn); } } private void FillTreeViewByIntezmeny() { tvHatosag.BeginUpdate(); tvHatosag.Nodes.Clear(); List<Hatosag> HatosagLista = Data.GetHatosagTreeViewSource(Convert.ToInt32(cbIntezmeny.SelectedValue.ToString())); LoadHatosagTreeViewNodes(HatosagLista, null); tvHatosag.EndUpdate(); tvHatosag.Refresh(); } . . . /* Data Access Layer */ private void FillHatosagList(ref int ID, int HatosagID, int Level, DataRow FilterRow, ref Hatosag hatosag, List<Hatosag> HatosagLista) { DataRow[] rows = Ds.Tables["TVCList"].Select("H_ID = " + HatosagID.ToString() + " AND Level = " + Level); DataRow dr; SqlDataAdapter Sda = new SqlDataAdapter(); DataTable tbl = new DataTable(); int ParentID = ID; if (rows.Count() > 0) { dr = rows[0]; #region Gyökér tétel //Annyi sor lesz ahány szint van. Mivel a Level-re is megszűrjük így csak 1 szint lesz maximum. if (dr.IsNull("LinkMasterFields")) { //Gyökér, tehát ez a legfelsőbb szint Sda.SelectCommand = new SqlCommand(dr["RecordSource"].ToString(), Connection); Sda.Fill(tbl); foreach (DataRow drtbl in tbl.Rows) { ID++; Hatosag tmpHatosag = new Hatosag(); tmpHatosag.ID = ID; tmpHatosag.ParentID = ParentID; tmpHatosag.Megnevezes = drtbl["Megnevezes"].ToString(); if (Enum.IsDefined(typeof(HatosagDataType), Convert.ToInt32(dr["HatosagTipus"].ToString()))) { tmpHatosag.HatosagTipus = (HatosagDataType)Enum.Parse(typeof(HatosagDataType), dr["HatosagTipus"].ToString(), true); } else { tmpHatosag.HatosagTipus = HatosagDataType.Hatosag; } tmpHatosag.Szuro = ""; FillHatosagList(ref ID, HatosagID, Level + 1, drtbl, ref tmpHatosag, HatosagLista); HatosagLista.Add(tmpHatosag); } } #endregion #region Gyermek tétel else { //Gyermek tételek //A paraméternek megfelelően beállítjuk a szűrőfeltételt string tmpSQL; tmpSQL = dr["RecordSource"].ToString().Substring(0, dr["RecordSource"].ToString().IndexOf("=[P]") + 1) + "'" + FilterRow[dr["LinkMasterFields"].ToString()] .ToString() + "'"; //dr["RecordSource"].ToString().IndexOf("=[P]") Sda.SelectCommand = new SqlCommand(tmpSQL, Connection); Sda.Fill(tbl); foreach (DataRow drtbl in tbl.Rows) { ID++; Hatosag tmpHatosag = new Hatosag(); tmpHatosag.ID = ID; tmpHatosag.ParentID = ParentID; tmpHatosag.Megnevezes = drtbl["Megnevezes"].ToString(); if (Enum.IsDefined(typeof(HatosagDataType), Convert.ToInt32(dr["HatosagTipus"].ToString()))) { tmpHatosag.HatosagTipus = (HatosagDataType)Enum.Parse(typeof(HatosagDataType), dr["HatosagTipus"].ToString(), true); } else { tmpHatosag.HatosagTipus = HatosagDataType.Hatosag; } tmpHatosag.Szuro = ""; if (hatosag.HatosagList == null) hatosag.HatosagList = new List<Hatosag>(); //Csak akkor hozunk létre új listát, ha az még nincsen létrehozva FillHatosagList(ref ID, HatosagID, Level + 1, drtbl, ref tmpHatosag, HatosagLista); hatosag.HatosagList.Add(tmpHatosag); } } #endregion } } public List<Hatosag> GetHatosagTreeViewSource(int HatosagID) { const int StartLevel = 1; List<Hatosag> tmpList = new List<Hatosag>(); Hatosag hat = new Hatosag(); int ID = 0; FillHatosagList(ref ID, HatosagID, StartLevel, null, ref hat, tmpList); return tmpList; }

    Továbbgyorsítási ötleteket még mindig szívesen fogadok

    W.
    Mutasd a teljes hozzászólást!
  • Ez adta meg a kezdő lökést a helyes irányhoz:

    How To Use Hierarchical DataTemplate in WPF
    Mutasd a teljes hozzászólást!
  • Én nem nagyon értem, miért kell előre betölteni az adatokat.

    Mit csinálsz majd, amikor 4-szer ennyi adatod lesz? (Azt ne mondd, hogy nem lesz...)
    Mutasd a teljes hozzászólást!
  • Szerintem pedig az lenne a legtisztább sor, ha beraknál egy Progress Bar-t amit egy thread kezel. Be kell ismerni a felhasználó előtt, hogy nem egy egyszerű műveletről van szó és ez bizony kis időbe telik. Na jó nem órákat kell ott ülnie a felhasználónak mire betölti az adatokat az "Utóbbi 50 év választási adatai" című adatbázisból, hanem nyavalyás 4 másodpercet. A progress bár végig fut hamar és már ott is van neki az adatai. Jobban lefogja kötni, az hogy a Progress Bar de szépen megy előre, minthogy lesse az adatait a képernyőn. Egy videó renderelés, program telepítés is időigényes folyamat akár csak a te esetedben.
    Mutasd a teljes hozzászólást!
  • A Progressbaron agyaltam én is már és lehet, hogy ez lesz. Homokóra már van;)
    Mutasd a teljes hozzászólást!
  • Ha 4-szer ennyi lesz akkor valszeg átgondolom a kérdést és akkor az már tényleg más megközelítést fog igényelni.

    Viszont azt kell mondanom, hogy nem lesz. Ez, ami 10-12 mp-re megfogta a betöltést az kirívó és NEM jellemző adathalmaz.

    A többi amit megjelenítek az jellemzően 3000-4000 tétel.

    Ez a program egy Access-ben Data Outline Control-lal megvalósított program átirata lesz. A DOA rohadt gyorsan össze tudja szedni az adatokat.

    Hasonló kellene nekem .NET alá is, ha van, de egyelőre marad a TreeView.

    W.
    Mutasd a teljes hozzászólást!
  • Amit javasolsz (ha jól értem) az az, hogy első körben csak a főbb tételeket töltsem be és csak akkor töltsem be az altételeket, ha rányomok az adott ág [+]-ára...?

    W.
    Mutasd a teljes hozzászólást!
  • Ehhez hozzáfűznék annyit, hogy a Programtervezési Minták könyv Helyettes mintája az amire Kukipapa utal. Ott is olyan példát hoz, hogy ha betöltesz egy doksit és azon vannak nagy méretű dolgok(táblázatok, képek), akkor amíg a felhasználó nem görget oda addig csak egy úgynevezett helyettes vagy proxy töltődik be. Ennek nincs sok időigénye, mert alapvető információkat tölt be róla(méret, stb.), a legköltségesebb dolgokat nem. Amikorra odagörget a felhasználó akkor fogja betölteni a tényleges táblázatot, képet. Így nem egy időben egyszerre kell mindent betölteni, hanem szépen elosztva mindig egy keveset így gyorsabb. Mintha nem 18 ezer elemed lenne, hanem csak 1-2 ezer. Te is mondtad, hogy pár elemnél ez megfelelő. Egyszerre úgyse fogja látni a felhasználó, mind az összes adatot, mert az fizikai képtelenség. Akkor az összes NodePoint-nak ki kellene legyen nyitva és a monitornak házfal méretűnek kellene, hogy legyen hogy az összes adat kiférjen.

    Szóval Kukipapa mond valamit

    Mondjuk nekem még mindig fúrja az oldalamat, hogy én a B osztályú IP címekkel(65000 darab) egy DataGridView kevesebb mint 4 sec alatt töltöttem fel, de ott csak egy mezei értékadásról volt szó:

    dataGridView1.DataSource = filteredList;
    Mutasd a teljes hozzászólást!
  • Én el is fogadom, hogy Kukipapa-nak igaza vagyon:)
    Mutasd a teljes hozzászólást!
  • És a listád összerakása mennyi ideig tartott? Azt mérted?

    W.
    Mutasd a teljes hozzászólást!
  • Persze, ezt írtam már legelőször is.

    Alapesetben csak a root elemeket töltsd be, NodeMouseDoubleClick esemény hatására pedig kizárólag a megnyitott Node elemeit töltsd föl (utána azok már a memóriában maradnak). Maga az adatforrás lehet a memóriában, de akár jöhet közvetlenül adatbázisból, hiszen limitált számú rekord jön csak onnan.

    Felhasználói élmény alapján az eredmény ugyanaz, mintha előre töltenéd föl egyben, és nem kell aggódnod a jövőbeli lassúság miatt sem.
    Mutasd a teljes hozzászólást!
  • Igen, ez tényleg kevesebb időt igényel. Viszont az adott tételek altétel szűrőit el is kell tárolnom addig, hogy tudjam, mi tartozik az adott tétel alá (Táblanév + Szűrőfeltétel). Erre, gondolom, csak a .tag tulajdonság alkalmas.

    W.
    Mutasd a teljes hozzászólást!
  • Nem mértem sajnos. A listát elsőnek feltöltöttem az IP címekkel. A lista saját típusú objektumok voltak, mint neked a Hatosag, nekem is voltak mezők, de én csak az IP Address mezőt töltöttem fel. Ezt utána odaadtam a datagridview datasourcejának. Azt úgy emlékszem csak egyszer kellett odaadni. Utána fogtam x szálat, nekem mondjuk 512 darab volt. Azok mentek végig szépen a listán, kivették az IP-t megpingelték utána a kapott értékkel feltöltötték a lista maradék mezőit. Ezek aztán megjelentek a táblában is. Tehát nekem nem kellett hivatkozni a datagridview cellájára úgy mint neked a TreeView Node-jaira
    Mutasd a teljes hozzászólást!
  • Nem ismerem a pontos adatbáziszerkezetedet, de általánosságban elmondható, hogy a Tag property egy objektum, azt teszel bele, amit szeretnél (így akár komplex információt is, nemcsak egy string lehet).

    Valószínűleg lehetne gyorsítani a kódodon is, de teljesen felesleges - ekkora adatmennyiségben a felhasználó úgyis keresni akar majd, nem egyben böngészni.

    Amennyiben egy egyszerű node feltöltése is lassúnak bizonyul, nos akkor viszont megkerülhetetlen lesz.

    ----------

    Példa a Tag használatára. Tegyük fel, itt az osztályod, amiben a node-hoz tartozó táblanevet és szűrőt tárolod.

    public class TVNodeData { public string TableName { get; set; } public string Filter { get; set; } }

    A kiolvasó kód:

    private void treeView1_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e) { TVNodeData data = e.Node.Tag as TVNodeData; }

    A data nevű változó tartalmazza annak a Node-nak a Tag property-jében eltárolt adatát, amire a felhasználó duplán clickelt.
    Mutasd a teljes hozzászólást!
  • Sziasztok!

    Megvan a megoldás:)

    Köszönhetően a tanácsodnak és a hierarchikus adatszerkezetnek.:)

    A következőt kreáltam (csak a releváns kódot másolom be, a listafeltöltése és a lista alapját adó struct maradt amit fentebb már vázoltam):

    A legfelsőbbszintet betöltő kód:

    class HatosagNodeSource { public Hatosag hatosag; public bool ChildAdded = false; } private void FillTreeViewByIntezmeny() { try { // Suppress repainting the TreeView until all the objects have been created. tvHatosag.BeginUpdate(); // Clear the TreeView each time the method is called. tvHatosag.Nodes.Clear(); List<Hatosag> HatosagLista = Data.GetHatosagTreeViewSource(Convert.ToInt32(cbIntezmeny.SelectedValue.ToString())); LoadHatosagTreeViewTopNodes(HatosagLista); } finally { tvHatosag.EndUpdate(); tvHatosag.Refresh(); } } private void LoadHatosagTreeViewTopNodes(List<Hatosag> HatosagLista) { //Csak a felső szinteket töltjük fel //Az alsóbb szintek akkor jelennek meg, ha lenyitják a szintet foreach (Hatosag hat in HatosagLista) { HatosagNodeSource HNS = new HatosagNodeSource(); HNS.hatosag = hat; TreeNode tn = new TreeNode(hat.Megnevezes); tn.ForeColor = Color.DarkBlue; tn.NodeFont = new Font(tvHatosag.Font, FontStyle.Bold); //Ha vannak gyermekei akkor hozzáadunk egy sima üres sort, mert azzal tudjuk csak megjeleníteni a [+] szintnyitó jelet if (hat.HatosagList != null) tn.Nodes.Add("-"); tn.Tag = HNS; tvHatosag.Nodes.Add(tn); } }

    Gyermek szintet betöltő kód (Mikor lenyitjuk a [+]-ra kattintva => Expand):

    private void tvHatosag_AfterExpand(object sender, TreeViewEventArgs e) { DoFillHatosagChildNodes(e.Node); } private void DoFillHatosagChildNodes(TreeNode ParentNode) { Cursor tmpCursor = this.Cursor; this.Cursor = Cursors.WaitCursor; try { try { try { // Suppress repainting the TreeView until all the objects have been created. tvHatosag.BeginUpdate(); LoadHatosagTreeViewChildNodes(ParentNode); } finally { tvHatosag.EndUpdate(); } } catch (Exception ex) { MessageBox.Show(ex.Message, "HIBA", MessageBoxButtons.OK, MessageBoxIcon.Error); } } finally { this.Cursor = tmpCursor; } } private void LoadHatosagTreeViewChildNodes(TreeNode ParentNode) { if (!(ParentNode.Tag as HatosagNodeSource).ChildAdded) { //Ha még nem adtuk hozzá az altételeket //Töröljük az alibiből hozzáadott 1 node-ot ParentNode.Nodes.Clear(); foreach (Hatosag hat in (ParentNode.Tag as HatosagNodeSource).hatosag.HatosagList) { HatosagNodeSource HNS = new HatosagNodeSource(); HNS.hatosag = hat; TreeNode tn = new TreeNode(hat.Megnevezes); tn.ForeColor = Color.DarkBlue; tn.NodeFont = new Font(tvHatosag.Font, FontStyle.Bold); //Ha vannak gyermekei akkor hozzáadunk egy sima üres sort, mert azzal tudjuk csak megjeleníteni a [+] szintnyitó jelet if (hat.HatosagList != null) tn.Nodes.Add("-"); tn.Tag = HNS; ParentNode.Nodes.Add(tn); } (ParentNode.Tag as HatosagNodeSource).ChildAdded = true; } }

    Amint láthatod annyit javítottam a dolgon, hogy nincsen szükség NodeMouseDoubleClick eseményre hisz ahol van gyermek ott van [+] szintnyitó is.

    Köszönöm a javaslatodat.

    Szerdzso: köszönöm neked is az iránymutatást. Az ajánlott programtervezési mintának utána fogok nézni.

    Tisztelettel:
    Wowbagger The Infinitely Prolonged
    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