Gdy tworzymy aplikacje okienkowe w .NET z użyciem Windows Forms, możemy korzystać z mnóstwa (co najmniej kilkudziesięciu) typów kontrolek dostępnych out-of-the-box. Nie wszystkie nawet mają rację bytu jako rzeczywiste kontrolki, ale w wielu przypadkach fakt, że nimi są, ułatwia korzystanie z API, które się kryje za taki komponentami. (Przykładem jest kontrolka BackgroundWorker).
Nie oznacza to jednak, że nie istnieje czasami potrzeba stworzenia własnego rodzaju kontrolki, specyficznej dla pisanego programu. Nawet jeśli miałaby ona być użyta tylko w jednym egzemplarzu, wyodrębnienie jej logiki poza zasadniczy kod aplikacji powinno wyjść im obu na dobre. W tym sensie jest ten rodzaj dodatkowej warstwy abstrakcji, który zazwyczaj opłaca się stworzyć.
Jak to się robi? Przede wszystkim należy wiedzieć, że w .NET kontrolki definiowane przez programistę mogą być jednego z trzech rodzajów. Stosunkowo najprostszym jest user control, które to stanowi po prostu pojemnik na kilka innych kontrolek zebranych w całość. Mogą to być na przykład dwa obiekty typu
NumericUpDown
opatrzone etykietami “Od” i “Do”, jeśli w naszym programie wielokrotnie i w różnych miejscach zachodzi potrzeba podawania przedziału liczbowego. Właściwości takiej customowej kontrolki są najczęściej bezpośrednio mapowane na właściwości kontrolek składowych, a zdarzenia są sygnalizowane w odpowiedzi na niektóre ze zdarzeń pochodzących z tychże kontrolek. W sumie więc można powiedzieć, że trochę tak jak funkcje i klasy pozwalają na wielokrotne wykorzystywanie kodu, tak user controls dają możliwość ponownego wykorzystania pewnych fragmentów UI.
Drugim typem są kontrolki dziedziczone (inherited controls). Nazwa wskazuje, że powstają one przez odziedziczenie już istniejącego rodzaju (klasy) kontrolki i dodanie do niej lub zmianę funkcjonalności. Może to obejmować dodanie nowych właściwości, częściowego lub całkowitego obsłużenia niektórych zdarzeń i inne tego typu modyfikacje zachowania kontrolki. Ważne jest tutaj to, iż efekt, jaki chcemy osiągnąć, jest na tyle zbliżony do jednej z istniejących kontrolek, że można ją wykorzystać i nie zaczynać od zera.
No ale nie zawsze tak jest i czasem naprawdę trzeba zacząć od podstaw. Jeżeli bazujemy na zupełnie abstrakcyjnym typie z góry hierarchii interfejsu – jak Control
czy Component
– to mamy do czynienia z kontrolką typu owner-draw. Dla niej musimy ręcznie rysować całą zawartość przy pomocy instrukcji GDI+ (stąd nazwa), opierając się przy tym na prostych zdarzeniach w rodzaju kliknięć myszy. Nie jest to więc łatwe i szybkie do wykonania zadanie.
Bywa aczkolwiek i tak, że jest ono koniecznie. Zanim się do niego zabierzemy, lepiej jednak przejrzeć alternatywy w postaci kontrolek odziedziczonych lub user controls. Możliwe, że w ten sposób zaoszczędzimy sobie pracy.
A jak to jest ze zmainą zachowania standardowych kontrolek typu EditBox? Rozumiem, że nie ma problemu z eventami, a co gdybym chciał sam zająć się rysowaniem takiej kontrolki? O ile mi wiadomo sama klasa EditBox jest tylko wrapperem na natywne funkcje WinAPI.
Dziedzicząc po EditBox, da się override’ować metody, np. te od rysowania jak OnPaint czy Refresh. Trudno jednak powiedzieć, jak by to wpłynęło na zachowanie kontrolki będącej – w tym przypadku – wrapperem na klasę EDIT z Windows API. Możliwe, że działałaby tak samo, a tylko rysowała się w customowy sposób. Trudno jednak przewidzieć, czy nie spowodowałoby to problemów z jej obsługą (np. klikamy w jakieś miejsce, w którym standardowo byłby wpisany tekst, ale przy naszym sposobie rysowania np. czcionka jest mniejsza i żadnego tekstu tak naprawdę tam nie ma – a mimo to pozycja kursora ulega zmianie; itp. itd.).
Ja ostatnio napotkałem taki problem, że kontrolki .NET ListView i TreeView migają, kiedy je odświeżam używając owner-drawingu. Dla ListView wystarczyło włączyć DoubleBuffering, ale ta prosta właściwość typu bool jest – co za absurd – protected, więc specjalnie dla jej przestawienia trzeba klasę wydziedziczyć. Natomiast w przypadku TreeView nawet to nie pomaga, bo właściwość DoubleBuffering jest, ale nie działa, co jest oficjalnie potwierdzone.
Chciałbym dodać właściwośc do kontrolki utworzonej przeze mnie tak aby w toolbox’ie pokazywał się mój opis i moja ikno przy kontrolce a nie “Version 1.0.7.33 .NET Component”. Wiem jak dodawać metody aby były widoczne w “Properties” w odpowiedniej grupie i w własnym opisem ale jak zrobić to dla całej kontrolki.
Z góry dzięki za pomoc