Vydělávej až 160.000 Kč měsíčně! Akreditované rekvalifikační kurzy s garancí práce od 0 Kč. Více informací.
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.
Avatar
tomas
Člen
Avatar
tomas:15.8.2014 14:03

Ahoj všem. Nevím si rady s dynamickým naplněním TreeView. Mám tabulku ve formátu id, parrentID, nazev. Tabulku načítám pomocí LINQ v tom problém nemám, ale nevím jak data dostat do TreeView. Problém je v tom, že předem nevím, kolik má který rodič potomků. Když bych mě předem jasný počet potomků, tak udělám potřebný počet vnořených smyček. Už jsem toho prolezl hodně, ale nikde jsem nenašel rozumné řešení.

 
Odpovědět
15.8.2014 14:03
Avatar
Jan Vargovský
Tvůrce
Avatar
Odpovídá na tomas
Jan Vargovský:15.8.2014 16:00

Nějak nechápu co na tom konkrétně neumíš. Plus by bylo vhodné říct v jaké technologii to děláš.

 
Nahoru Odpovědět
15.8.2014 16:00
Avatar
tomas
Člen
Avatar
tomas:20.8.2014 21:51

Ahoj, programuju v C#. Mám následující tabulku.

- id - parentID - nazev
- 1 - 0 - a
- 2 - 1 - b
- 3 - 1 - c
- 4 - 3 - d
- 5 - 4 - e

z toho je jasné kdo je rodič a kdo je potomek. Jednoduchým cyklem si projdu tabulku a přidám nody.

IEnumerable<Lokace> lok = db.Lokace.ToArray();
foreach (Lokace lk in lok)
  {
    TreeNode node = new TreeNode();
    node.Text = lk.nazev.ToString();
    node.Value = lk.id.ToString();

    if (lk.ParrentID != 0)
    {
      TreeNode tn = TreeView1.FindNode(Convert.ToString(lk.ParrentID));
      tn.ChildNodes.Add(node);
    }
    else
    {
      TreeView1.Nodes.Add(node);
    }

V tomto případě to ale vyhodí chybu při 4 průchodu smyčky. Jde o to, že metoda FindNode hleda hodnotu ValuePath. Při prvním průchodu a vložení prvního záznamu je valuePath prvního(root) nodu 1, to znamená, že v nasledujícím průchodu mě findNode najde nadřazený prvek, vloží do proměné tn a já můžu přiřadit potomka. Jenže node s ID 2 a 3 už mají valuePath 1/2(1/3) Což značí kam patří. U čtvrtého nodu tedy FindNode("3") nenajde nic. Potřebuji přidat potomka do nodu s valuePath "1/3". Tím pádem vyhodí následující řádek chybu, protože je mimo index. ValuePath s hodnotou 3 totiž neexistuje. A v tom je kámen úrazu. Předem to nevím jaká bude valuePath. Takže jak z toho ven? Napadlo mě udělat jeden vložený cyklus, který by prošel všechny nody a pak hledat v nalezených řetezcích hodnotu 3, ale to není dost dobře použitelný. Takže jak mám najít a přidat potomka k potomkovi? Ideální by bylo, když by jsem mohl hledat podle value, protože v ní mám jedinečný ID a měl bych tak jistotu, že dám prvek tam kam patří.

Snad jsem to popsal srozumitelně.

Editováno 20.8.2014 21:53
 
Nahoru Odpovědět
20.8.2014 21:51
Avatar
sadlomaslox25:20.8.2014 22:50

Napis si vlastni rekurzivni vyhledavani pro TreeNodeCollection.

 
Nahoru Odpovědět
20.8.2014 22:50
Avatar
Jan Vargovský
Tvůrce
Avatar
Odpovídá na tomas
Jan Vargovský:20.8.2014 22:59

Ahoj, to že je to C# mi došlo, ale šlo mi spíše o to jestli WF nebo WPF.

Ze tvého příkladu mi vyšlo něco takového (viz. obrázek dole). Nějak jsem nepřišel na to, proč by ti to někde něco nemělo najít. Každopádně jestli nemáš přesně zadanou db tabulku, tak to raději udělej skrz jednoduchou třídu:

class Location
{
    public int Id { get; set; }
    public Location Parent { get; set; }
    public IList<Location> SubLocations { get; set; }
    public string Name { get; set; }

    public Location(int id, string name)
    {
        Id = id;
        Name = name;
        SubLocations = new List<Location>();
    }

    public void AddSubLocation(Location loc)
    {
        SubLocations.Add(loc);
        loc.Parent = this;
    }
}

Trošku jsem ti ale upravil vstupní data, tak kdyžtak upřesni jak přesně to s nimi je.

Pak teda podle tebe vstupní data vypadají takto:

Location a = new Location(1, "a");
Location b = new Location(2, "b");
Location c = new Location(3, "c");
Location d = new Location(4, "d");
Location e = new Location(5, "e");

a.AddSubLocation(b);
a.AddSubLocation(c);
c.AddSubLocation(d);
d.AddSubLocation(e);

var locactions = new List<Location> { a }; // to jen, že hlavních lokací tam máš asi víc, už podle příkladu.

No a nacpat to do TreeView už je jen rekurze..

private void FillTreeView(TreeView treeView, IEnumerable<Location> locations)
{
    foreach (Location loc in locations)
        treeView.Items.Add(CreateNode(loc));
}

private TreeViewItem CreateNode(Location location)
{
    TreeViewItem actual = new TreeViewItem() { Header = location.Name };

    foreach (Location subLocation in location.SubLocations)
        actual.Items.Add(CreateNode(subLocation));

    return actual;
}

Kdyžtak upřesni jak to máš s těmi daty, to zpětné hledání rodiče mi přijde zbytečné :)

Btw, je to psáno ve WPF, takže na WF si tam musíš upravit pár věci (Items -> Nodes, TreeViewItem -> TreeNode, ...).

Editováno 20.8.2014 23:00
 
Nahoru Odpovědět
20.8.2014 22:59
Avatar
tomas
Člen
Avatar
Odpovídá na Jan Vargovský
tomas:21.8.2014 8:54

Ok, dík, mrknu na to a dám vědět, Jinak to píšu ve WF.

 
Nahoru Odpovědět
21.8.2014 8:54
Avatar
tomas
Člen
Avatar
tomas:21.8.2014 16:23

Koukal jsem na to a ten kód chápu. Ale není mě jasná jedna věc. Jak vytvořím programově za běhu objekty a,b,c,d,e a následně je programově přidám k rodičům? Nemůžu je psát deklarativně, potřebuji je napsat programově. Protože chci kód použít na několik druhů stromů, které se často mění. Proto jsem to řešil postupně načtením jednoho záznamu a vyhledání rodiče ke kterému patří a přidal.

 
Nahoru Odpovědět
21.8.2014 16:23
Avatar
tomas
Člen
Avatar
tomas:22.8.2014 12:53

Tak jsem to nakonec vyřešil rekurzivní metodou, která mě vrátí celou cestu k rodiči.

protected string GetValuePath(IEnumerable<Lokace> lokace, int id)
{

    string valuePath = "";
    string valuePathBack = "";
    Lokace lok = (from lk in lokace
                 where lk.id == id
                 select lk).Single();

    valuePath = Convert.ToString(lok.id);
    int parent = Convert.ToInt32(lok.ParrentID);

    if (parent != 0)
    {
        valuePathBack = GetValuePath(lokace, parent) + "/" + valuePath;
    }
    else
    {
        return valuePath;
    }
    return valuePathBack;
}

Následně ji válím při průchodu tabulkou s celým stromem

protected void Button1_Click(object sender, EventArgs e)
{
    IEnumerable<Lokace> lok = db.Lokace.ToArray();
    foreach (Lokace lk in lok)
    {
        TreeNode node = new TreeNode();
        node.Text = lk.nazev.ToString();
        node.Value = lk.id.ToString();

        if (lk.ParrentID == 0)
            TreeView1.Nodes.Add(node);
        else
        {
            TreeNode tn = TreeView1.FindNode(GetValuePath(lok, Convert.ToInt32(lk.ParrentID)));
            tn.ChildNodes.Add(node);
        }

    }
}

Nevím jestli je to v správný postup, ale dá se to aplikovat na jakýkoliv strom.

Editováno 22.8.2014 12:55
 
Nahoru Odpovědět
22.8.2014 12:53
Avatar
Jan Vargovský
Tvůrce
Avatar
Odpovídá na tomas
Jan Vargovský:22.8.2014 17:30

Proč není signatura té metody taková?

protected string GetValuePath(Lokace lokace)

Foreachuješ všechny lokace a pak je znova hledáš uvnitř té metody.

 
Nahoru Odpovědět
22.8.2014 17:30
Avatar
tomas
Člen
Avatar
Odpovídá na Jan Vargovský
tomas:25.8.2014 11:19

Hmm dost dobře nechápu jak to myslíš. Teda chápu tu signaturu, ale jak načtu ty jeho rodiče, když zavolám tu metodu jen s jediným objektem? Budu vědět, že má nějakého předka, ale když ho zavolám znovu, nemám mu přece co předat.

 
Nahoru Odpovědět
25.8.2014 11:19
Avatar
Jan Vargovský
Tvůrce
Avatar
Odpovídá na tomas
Jan Vargovský:25.8.2014 19:37

Jo nic, zapomeň na to. Neviděl jsem tam tu rekurzi.

 
Nahoru Odpovědět
25.8.2014 19:37
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 11 zpráv z 11.