Zine.net online

Witaj na Zine.net online Zaloguj się | Rejestracja | Pomoc
w Szukaj

arkadiusz.wasniewski

TreeNode w wersji koguciej

Kilkukrotnie już zdarzyło się, iż potrzebowałem klasy, która umożliwiłaby zapamiętanie typowanych (typed, generic) struktur hierarchicznych (hierarchical collection) czyli dowolnego obiektu wraz z jego elementami potomnymi. W ramach platformy .NET istnieją już klasy implementujące podobną funkcjonalność. Mowa tu oczywiście o TreeNode z TreeNodeCollection oraz o, bardziej hermetycznym, MenuItem wraz z wewnętrznym MenuItemCollection. Klasy przeznaczone do obsługi menu trudno byłoby użyć do własnych rozwiązań. TreeNode jest zaś “ciężka” i brak w niej typowania, czyli możliwości określenia typu przechowywanego obiektu (precz z rzutowaniem!).

Z tego też powodu stworzyłem razu pewnego własną implementację struktury hierarchicznej. Nie jest ona skomplikowana. Punktem wyjścia jest klasa przechowująca dane wraz z kolekcją elementów potomnych:

    internal class LightTreeNode<T>

    {

        private readonly T _item;

        private readonly LightTreeNodeCollection<T> _nodes;

 

        public LightTreeNode(T item)

        {

            _item = item;

            _nodes = new LightTreeNodeCollection<T>(this);

        }

 

        public T Value

        {

            get { return _item; }

        }

 

        public LightTreeNodeCollection<T> Nodes

        {

            get { return _nodes; }

        }

    }

Kolekcja przechowująca potomków dla ułatwienia operowania implementuje interfejs ICollection<T>:

    internal class LightTreeNodeCollection<T> : ICollection<LightTreeNode<T>>

    {

        private readonly List<LightTreeNode<T>> _list;

        private readonly LightTreeNode<T> _owner;

 

        public LightTreeNodeCollection(LightTreeNode<T> owner)

        {

            _owner = owner;

            _list = new List<LightTreeNode<T>>();

        }

 

        public LightTreeNode<T> Owner

        {

            get { return _owner; }

        }

 

        public LightTreeNode<T> Add(T item)

        {

            var node = new LightTreeNode<T>(item);

            _list.Add(node);

            return node;

        }

 

        #region Implementation of IEnumerable

 

        public IEnumerator<LightTreeNode<T>> GetEnumerator()

        {

            return _list.GetEnumerator();

        }

 

        IEnumerator IEnumerable.GetEnumerator()

        {

            return GetEnumerator();

        }

 

        #endregion

 

        #region Implementation of ICollection<LightTreeNode<T>>

 

        public void Add(LightTreeNode<T> item)

        {

            _list.Add(item);

        }

 

        public void Clear()

        {

            for(int i = 0; i < _list.Count; i++){

                _list[i].Nodes.Clear();

            }

            _list.Clear();

        }

 

        public bool Contains(LightTreeNode<T> item)

        {

            return _list.Contains(item);

        }

 

        public void CopyTo(LightTreeNode<T>[] array, int arrayIndex)

        {

            _list.CopyTo(array, arrayIndex);

        }

 

        public bool Remove(LightTreeNode<T> item)

        {

            int index = _list.IndexOf(item);

            if(index < 0){

                return false;

            }

            _list[index].Nodes.Clear();

            _list.Remove(item);

            return true;

        }

 

        public int Count

        {

            get { return _list.Count; }

        }

 

        public bool IsReadOnly

        {

            get { return false; }

        }

 

        #endregion

    }

Przykład zastosowania to chociażby przygotowanie dla widoku (View) poleceń menu z poziomu prezentera (Presenter, Presentation Model):

            var menu = new LightTreeNode<Command>(new Command("Opcje"));

            LightTreeNode<Command> submenu = menu.Nodes.Add(

                new Command("Nawigacja"));

            submenu.Nodes.Add(new Command("Pierwszy", MoveFirst));

            submenu.Nodes.Add(new Command("Ostatni", MoveLast));

PS. Dla uproszczenia kodu usunięto wszystkie wywołania Debug.Assert sprawdzające poprawność wywołań.

Opublikowane 20 grudnia 2009 17:30 przez arkadiusz.wasniewski

Komentarze:

 

dotnetomaniak.pl said:

Dziękujemy za publikację - Trackback z dotnetomaniak.pl

grudnia 20, 2009 19:50
 

_mc2 said:

Fajne. Aż się prosi jeszcze o implementację wzorca Visitor

grudnia 21, 2009 13:54
 

arkadiusz.wasniewski said:

@_mc2: W którym miejscu?

grudnia 21, 2009 16:20
 

Twitter Trackbacks for arkadiusz.wasniewski : TreeNode w wersji koguciej [zine.net.pl] on Topsy.com said:

grudnia 21, 2009 18:15
Komentarze anonimowe wyłączone
W oparciu o Community Server (Personal Edition), Telligent Systems