Control pro stromovou strukturu   zodpovězená otázka

VB.NET, WinForms

Jaký control používáte pro zobrazení stromové struktury ?

U TreeView bych potřeboval možnost přidat sloupce s kolekcí subitems.

U ListView mi chybí fukčnost nodes, groups jsou pouze v jedné úrovni,

stejné je to s DataGridView, kde opět chybí fukčnost nodes.

Existuje něco hotového (zdarma)?

Nebo musím vytvořit vlastní control?

1) Podědit treeview a dokreslit header a columns?

2) Podědit listview, odsadit listitems a dokreslit treewiew glyph a branches ?

3) Podědit datagridview a přidat vlastní vykreslený sloupec pro modes?

...

Nezkoušeli jste něco podobného či nemáte tip na nějaký pěkný příklad ?

Předem děkuji za případnou účast.

Hezký den!

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Kdysi (rok 2013) jsem napsal vlastní Windows Forms Control TreeListViewControl. Je to takovej hybrit Treeview/listview, umí zobrazit strom s více sloupci.

Zkuste jestli vám pomůže. K dispozici je zde:

http://www.h2net.cz/downloads/Libraries/...

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Vydal jsem se asi podobnou cestou, podědil jsem ListViewItem jako TreeListViewItem s vlastností Parent a kolekcí TreeNodes, pak ListView jako TreeListView a v něm sdílený Shared List Of TreeListViewItem, obešel jsem se bez Win32 API, použil jsem IndentCount pro odsazení v závislosti na aktuální úrovni a je-li zobrazena ikona, glyphs a branches jsem dokreslil manuelně, pomocí Visual Styles Rendereru se mi podařilo vykreslit pouze glyph, ostatní bez úspěchu.

Chybí mi dořešit, aby klíč byl v listu unikátní a potom seřazení, netuším, nejspíš nějaký vlastní SortComparer pro listview, aby se seřadilo po skupinách. Při tisícovce položek je to strašně pomalé, hojně používám Insert a vkládám položku po položce na dané místo, chci to nějak předělat pomocí CopyTo a vložit celý balík naráz na dané místo. Jako jinou odrůdu treelistview mám potřebu rozbalovat parentnode, které se kdesi ve struktuře může opakovat vícekrát, ale definováno je pouze jednou, stejné items nejde vložit znovu a bude nutné je klonovat. Vyzkouším vaší tvorbu, škoda, že nemohu vidět zdrojový kód, bylo by zajímavé vidět váš postup. Každopádně díky za odezvu a link na váš hybrid.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Tak to se omlouvám, neuvědomil jsem si, že v tom ZIPu mám jen release verzi.

Kompletní VS projekt jsem nahrál sem: http://www.h2net.cz/downloads/Libraries/...

Jen jsem z toho vyhodil můj .snk klíč, tak musíte ve vlastnostech projektu vypnout SignAssembly.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Moc se omlouvám za zvědavost, měsíc se trápím se svými pokusy ve VB.NET, tak jsem nakouknul pomocí překladače. Vyzkouším hotový control a vzdávám to. Muselo to dát strašnou práci.

Co licenční podmínky? Opravdu postačí pouze velké díky?

nahlásit spamnahlásit spam 0 odpovědětodpovědět

On ten control je už starší a já ho už nemám čas udržovat, takže možná nějakou úpravu potřebovat bude. Vyzkoušejte.

Control je volně k dispozici včetně zdrojových kódů (open source např. Apache License).

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Nastavil jsem target framework na full (jen to najít), referenci na hotový control a už to šlape.

Neuvažoval jsem nikdy o návrháři a jak jsem koukal, tak bych to nedal dohromady, moje potřeba je plnit vše za běhu s kontrolou existence rodiče a jeho získáním pomocí klíče.

Nejdřív jsem postrádal získání Node podle klíče(key), ale pomocí Name lze klíč u Node nastavit a nakonec mi připadá hbitější si připravít nodes do dictionary a potom je vložit pomocí AddRange.

Asi nic lepšího nevymyslím :

Dim nds As New System.Collections.Generic.Dictionary(Of String, TreeListNode)

'pridat rodice
Dim n As New TreeListNode("root")
With n
    .Name = root_key
    .SubItems.Add("abc")
End With
nds.Add(root_key, n)

Dim ch As New TreeListNode("child")
With ch
    .Name = child_key
    .SubItems.Add("abc")
End With
'pridat k rodici
n.Nodes.Add(ch)
nds.Add(child_key, ch)

'Dim b1 As Boolean = nds.ContainsKey(a_key) 'obsahuje-li klíč a_key

'Dim p As TreeListNode = Nothing
'Dim b2 As Boolean = nds.TryGetValue(key_of_p, p) 'ziskat rodice dle klice

'dale naplnit vse potrebne ...

'ziskat root nodes do pole, siroty bez rodice
Dim rn() As TreeListNode
rn = (From n As TreeListNode In nds.Values Where n.Parent Is Nothing).ToArray
'naprat pole, kde siroty jenom zustaly, do treelistview 
tlv.Nodes.AddRange(rn)

'pripadne rozbalit
tlv.ExpandAll() 

'dotaz viz nize
tlv.Sort()                        

Nedaří se mi správně seřadit čeština, např. Š se řadí za Z, hledal jsem něco ohledně vnuknutí culture, nejspíš vytvořit vlastní SortComparer, kde se u Compare předá CurrentCulture ?

Hluboká poklona tvůrci, bude-li čas, poprosím ještě o pomoc se seřazením, ale možná, že se tím nakonec nějak prokoušu, nechci zneužívat poskytnutý full service.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Pro řazení ve WinForms ListView jsem používal tento comparer, měl by snad jít použít i do toho TreeListView. Zkuste jestli to vyřeší váš problém se řazením.

/// <summary>
        /// Sorting objekt pro sloupce v ListView
        /// </summary>
        /// <remarks>
        /// Podpotuje změnu řazení Ascending/Descending při stejném sloupci
        /// </remarks>
        /// <example>
        /// private void lvw_ColumnClick(object sender, System.Windows.Forms.ColumnClickEventArgs e)
        /// {
        ///		// Set the ListViewItemSorter property to a new ListViewItemComparer 
        /// 	// object. Setting this property immediately sorts the 
        ///		// ListView using the ListViewItemComparer object.
        ///		lvw.ListViewItemSorter = new ListViewItemSimpleComparer(e.Column, (ListViewItemSimpleComparer)lvw.ListViewItemSorter);
        /// }
        /// </example>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")]
        public class ListViewItemSimpleComparer : IComparer, System.Collections.Generic.IComparer<ListViewItem>
        {
            #region member varible and default property initialization
            /// <summary>
            /// Sort column index
            /// </summary>
            private int m_Column;

            /// <summary>
            /// Sort order
            /// </summary>
            private SortOrder m_Order;

            /// <summary>
            /// Název datového pole pro sort místo textu sloupce 
            /// </summary>
            private string m_DataFieldName = "";
            #endregion

            #region constructors and destructors
            /// <summary>
            /// Default constructor
            /// </summary>
            public ListViewItemSimpleComparer()
            {
                m_Order = SortOrder.Ascending;
            }

            /// <summary>
            /// Constructor pro určení sloupce, vždy Ascending
            /// </summary>
            /// <param name="Column">Sort column index</param>
            public ListViewItemSimpleComparer(int Column)
            {
                m_Column = Column;
                m_Order = SortOrder.Ascending;
            }

            /// <summary>
            /// Constructor pro určení sloupce i změny řazení Ascending/Descending
            /// </summary>
            /// <param name="Column">Sort column index</param>
            /// <param name="Order">Sort order</param>
            public ListViewItemSimpleComparer(int Column, SortOrder Order)
            {
                m_Column = Column;
                m_Order = Order;
            }

            /// <summary>
            /// Constructor pro automatickou změnu řazení Ascending/Descending podle slopce a minulého řazení
            /// </summary>
            /// <param name="Column">Sort column index</param>
            /// <param name="lvic"><c>ListViewItemSorter</c> nastavený z minulého řazení</param>
            public ListViewItemSimpleComparer(int Column, ListViewItemSimpleComparer lvic)
            {
                int LastColumn = 0;
                SortOrder LastOrder = SortOrder.Ascending;

                if (lvic != null)
                {
                    LastColumn = lvic.m_Column;
                    LastOrder = lvic.m_Order;
                }

                if (LastColumn == Column)
                {
                    //Change order
                    m_Column = Column;
                    m_Order = (LastOrder == SortOrder.Ascending ? SortOrder.Descending : SortOrder.Ascending);
                }
                else
                {
                    m_Column = Column;
                    m_Order = SortOrder.Ascending;
                }
            }

            /// <summary>
            /// Constructor pro automatickou změnu řazení Ascending/Descending podle slopce a minulého řazení
            /// </summary>
            /// <param name="Column">Sort column index</param>
            /// <param name="lvic"><c>ListViewItemSorter</c> nastavený z minulého řazení</param>
            /// <param name="DataFieldName">Název datového pole pro sort místo textu sloupce</param>
            public ListViewItemSimpleComparer(int Column, ListViewItemSimpleComparer lvic, string DataFieldName)
            {
                int LastColumn = 0;
                SortOrder LastOrder = SortOrder.Ascending;

                if (lvic != null)
                {
                    LastColumn = lvic.m_Column;
                    LastOrder = lvic.m_Order;
                }

                if (LastColumn == Column)
                {
                    //Change order
                    m_Column = Column;
                    m_Order = (LastOrder == SortOrder.Ascending ? SortOrder.Descending : SortOrder.Ascending);
                }
                else
                {
                    m_Column = Column;
                    m_Order = SortOrder.Ascending;
                }

                m_DataFieldName = DataFieldName;
            }
            #endregion

            #region action methods
            /// <summary>
            /// Porovnání objektů <see cref="ListViewItem"/>
            /// </summary>
            /// <param name="x">První <see cref="ListViewItem"/></param>
            /// <param name="y">Druhý <see cref="ListViewItem"/></param>
            /// <returns>Výsledek porovnání</returns>
            public int Compare(object x, object y)
            {
                return Compare((ListViewItem)x, (ListViewItem)y);
            }

            /// <summary>
            /// Porovnání objektů <see cref="ListViewItem"/>
            /// </summary>
            /// <param name="x">První <see cref="ListViewItem"/></param>
            /// <param name="y">Druhý <see cref="ListViewItem"/></param>
            /// <returns>Výsledek porovnání</returns>
            public int Compare(ListViewItem x, ListViewItem y)
            {
                int result;

                if (string.IsNullOrEmpty(m_DataFieldName))
                {
                    //Porovnání podle textu SubItem
                    result = String.Compare(
                        x.SubItems[m_Column].Text,
                        y.SubItems[m_Column].Text, StringComparison.Ordinal);
                }
                else
                {
                    //Porovnání podle hodnoty datového pole
                    result = Comparer.Default.Compare(((DataRow)x.Tag)[m_DataFieldName],
                        ((DataRow)y.Tag)[m_DataFieldName]);
                }

                if (m_Order == SortOrder.Ascending)
                {
                    return result;
                }
                else
                {
                    return -result;
                }
            }
            #endregion
        }
nahlásit spamnahlásit spam 0 odpovědětodpovědět
                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.
  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:  
Heslo:  

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback