Sellest et WinFormsi designer seob arendajate käsi-jalgu..

Seoses hiljutise vajadusega Winforms rakenduse UI'd programmeerida, sai pisut komistatud Winformsi piirangute otsa..

VIsual Inheritance on puudustega

Visual inheritance on siis graafiliste elementide pärimine - näiteks kõikide vormide baasvormile logo panemine võiks käia VI kasutades vormide pärimisega, kus esimene vorm sisaldaks ainult logo ja kõik pärivad vormid saaksid õige logo kohe õigesse kohta. Baasvormi muudatused (näiteks logo vahetamine, mõõtmed jms kajastuks automaatselt kõigil vormidel. Ilus näide koodi korduvkasutatavusest ja UI standardiseerimisest. Paraku, nagu selgus, on enamasti kaval VI'd vältida

Visual inheritance töötas kenasti kuni Visual Studio.NET versioonini. Pärast seda ehitati asju niipalju ümber, et kadus tugi konteiner-komponentidele. VI kannab need pärija-vormile küll kenasti üle, aga nende property'd ei saa enam muuta. Control-id, mis seetõttu muutuvad üle VI tarbides kasutuks on näiteks:

  • Panel, FlowLayutPanel, TableLayoutPanel - mis kasu on paneelist designeris, kui sa ei saa sinna midagi sisse panna ?
  • DataGridView - ei mingid Designeris propery'te sättimist.
  • ... (neid on veel).

Käesolevas projektis ma leidsin, et eeltoodu põhjustel polegi mul VI'd vaja. Logo-control'i lohistamine on lollikindlam kui VI kõigi oma lollide piirangutega. Selle asemel võiks ju kasutada tavalist pärimist .. Selgus, et seegi ei ole nii lihtne:

 

Winforms vormid ei saa pärida generic-klassist

Kusjuures pärida tegelikult saab. Kood kompileerub kenasti ja isegi töötab kenasti. Paraku aga kaob sellega ära Designer-vaade ja asendub koleda ja segase veateatega. Kuna töövahenditega kaklemine ei ole lõbus siis seega on soovitatav Winforms vormide generic baasklasside kasutamist vältida või kasutada triviaalset häkki: luua proxy-klass vormi ja generic-klassi vahele. Sellest räägitakse ka näiteks siin.

Oluline näib olevat ka see, et baasklassil oleks parameetriteta konstruktor, kuna VS2008 Designer loob designeri avamisel baasklassist instantsi. Praktikas tähendab see seda, et sa ei saa pärida abstract markeriga baasklassist. Sama funktsionaalsus on küll saavutatav vastavad komponendid virtualina deklareerimisega, aga loomulikult ei ole see nii ilus lahendus. Samuti tuleb praktikas hoolitseda et baasklassi käivitamisel exceptionit ei visataks. Vajadusel on kaval design-ajal koodi üldse mitte jooksutada wrappides vea andva koodi näiteks nii:

   1:  if (LicenseManager.UsageMode != LicenseUsageMode.Designtime)
   2:  {
   3:      //this is called only in NOT design-mode:    
   4:  }

Tasub veel märkimist, et kuigi eelpool-toodud koodirea asemel saaks kasutada ka controli DesignMode property väärtust, siis see ei ole väga hea mõte, sest see ei tööta konstruktoris ja aktiivse designer-akna user-controlite koodis..

Design-time'i on võimalik debugida

Kuidas teada, mis koodi Visual Studio designTime'is käivitab ?
Lihtne.
Pane breakpoint sind huvitavasse kohta ja määra, et debugimisel käivitataks programmina VS devenv.exe, mis avab uue Visual Studio akna, kus saad õige solutioni laadida, ja erinevaid design-time aknaid avades breakpointidesse joosta.


Testid tehtud : VS2008 Professional Edition + Windows Server 2003