Avatar
tomas
Člen
Avatar
tomas:

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ý
Redaktor
Avatar
Odpovídá na tomas
Jan Vargovský:

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:

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:

Napis si vlastni rekurzivni vyhledavani pro TreeNodeCollection.

 
Nahoru Odpovědět 20.8.2014 22:50
Avatar
Jan Vargovský
Redaktor
Avatar
Odpovídá na tomas
Jan Vargovský:

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:

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:

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:

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ý
Redaktor
Avatar
Odpovídá na tomas
Jan Vargovský:

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:

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ý
Redaktor
Avatar
Odpovídá na tomas
Jan Vargovský:

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.