fbpx
devstyle.pl - Blog dla każdego programisty
devstyle.pl - Blog dla każdego programisty
2 minut

C# Power ponownie – Control.AllChildControls


30.08.2008

Podczas przygotowywania kolejnego posta z serii “Samples” zaimplementowało mi się coś bardzo fajnego, co chyba zasługuje na osobną notkę. Oto zatem kolejna krótka demonstracja potęgi połączonych mechanizmów C# (v. 2 i 3).
Scenariusz: mamy formatkę wypełnioną panelami, groupboxami, layoutami i wszystkimi innymi kontenerami jakie tam jeszcze Bozia z Redmond na toolbox wrzuciła. Nachodzi nas chętka na wykonanie pewnej operacji na WSZYSTKICH kontrolkach zawartych w oknie, niezależnie od tego gdzie są zagnieżdżone. Jak się do nich dobrać? Here comes the beauty of YIELD:

  1:  public static IEnumerable<Control> AllChildControls(this Control instance)
  2:  {
  3:  	foreach (Control control in instance.Controls)
  4:  	{
  5:  		yield return control;
  6:  		foreach (Control childControl in control.AllChildControls())
  7:  			yield return childControl;
  8:  	}
  9:  }

Wykorzystajmy to w jakimś interesującym przypadku… na przykład pod każdy TextBox podepnijmy ToolTipa pokazującego aktualną wartość właściwości Tag. Warunki z tego wynikające są dwa: kontrolka-dziecko musi być TextBoxem i jej Tag nie może być null. Na potęgę posępnego czerepu, LINQ przybywaj!!!

  1:  this.AllChildControls().OfType<TextBox>()
  2:  	.Where(tb => tb.Tag != null).ToList()
  3:  	.ForEach(tb => toolTip.SetToolTip(tb, tb.Tag.ToString()));

Może to jakieś zaćmienie, może za dużo kodowania bez przerwy, może nie widzę innego równie wyśmienitego rozwiązania, ale… jestem pod wrażeniem. Jak wyglądałby kod robiący to samo jeszcze kilkanaście miesięcy temu? Pewnie jakoś tak. Nie uzależniajmy się od technologii, ale wykorzystujmy w pełni to co nam oferuje!

Nie przegap kolejnych postów!

Dołącz do ponad 9000 programistów w devstyle newsletter!

Tym samym wyrażasz zgodę na otrzymanie informacji marketingowych z devstyle.pl (doh...). Powered by ConvertKit
Notify of
szogun1987
szogun1987

Byłaby ładna rekurencja i chyba nawet czytelniejsza :P

Procent

“AllChildControls” znajdziemy i w linii 1 (deklaracja) i w linii 6 (wywołanie samej siebie), więc rekurencję jak najbardziej mamy:)

ucel
ucel

Da sie to zrobic oszczedniej, ale wymaga implementacji ForEach dla IEnumerable. Zauwaz ze wywolujesz metode ToList(), co w efekcie podwoi wymagania pamieciowe kolekcji. Implementacja extension method ForEach() dla IEnumerable zlikwidowalaby ten problem . Z drugiej strony nie rozumiem dlaczego nie ma tego natywnie w System.Core :/.

Procent

Tak jest, też się nad tym zastanawiałem. “Przeszukałem nawet pół internetu” ale odpowiedzi nie znalazłem.
A co do podwojenia wymagań pamięciowych… czy na pewno? W obecnej postaci utworzona zostanie lista ze wszystkimi textboxami a dopiero potem niepotrzebne się odfiltrują. Z ForEach w IEnumerable filtrowanie odbędzie się na etapie tworzenia listy. Tak czy siak – wszystkie kontrolki już istnieją, więc gdzie może wystąpić dodatkowe zuzycie pamięci? ToList() wymusza po prostu wykonanie instrukcji o jeden krok wcześniej niż gdyby nastąpiło to po Where(). W efekcie od razu uzyskalibyśmy mniejszą listę.
Chyba że się mylę, wtedy z radością powitam wszelkie wyjaśnienia:)

apl
apl

@ucel: Z koncepcyjnego punktu widzenia zapytanie LINQ nie powinno wywoływać efektów ubocznych na elementach kolekcji, stąd brak metod takich jak ForEach, które ośmielałyby programistów do adopcji takiego modelu programowania. Jeśli spojrzeć z tej strony, to podejście Procenta jest słuszne: zapytanie jest formułowane i ewaluowane, a następnie elementy, które znalazły się w zbiorze wynikowym są przetwarzane. Inna sprawa, że możnaby zakończyć zapytanie zaraz po Where, a następnie użyć zwykłej pętli foreach do iteracji po wynikach. Rolę takiego deklaratywnego ForEacha w świecie LINQ może z powodzeniem pełnić operator Select: this.AllChildControls()   .OfType()   .Where(tb => tb.Tag != null)   .Select(tb => {… Read more »

Procent

Dzięki Olek za wyjaśnienia, szczególnie kwestii “dlaczego w System.Core nie zaimplementowano IEnumerable.ForEach”. “Koncepcyjny punkt widzenia” ma sens, nigdy w ten sposób na to nie spojrzałem.

ucel
ucel

No przeciez wlasnie cos takiego mialem na mysli ;)

Moja książka

Facebook

Zobacz również