Ho avuto un insidioso problema che mi ha fatto tribolare non poco oggi.
Sto creando una gestione di immagini via web (no Matteo, niente a che vedere con te :P) che permetta di caricare un immagine e cropparla, resizarla, girarla, controllarla. Insomma: un mini photoshop, ovviamente molto molto mooooooooolto mini :D
Ovviamente mi sono guardato in giro e nno ho visto niente che facesse come volevo io, tanti begli spunti alcuni fatti anche molto bene, ma mancavano di qualcosa oppure non mi convincevano per le soluzioni "tecnologiche" adottate (soprattutto per quanto riguarda CSS e Javascript). Quindi mi sono messo di impegno e mi sono creato il mio CustomControl, partendo da una base già pronta presente nell'azienda che faceva una cosa simile (upload di foto) ed espandendola.
Tutto andava perfettamente nei test, il controllo scheggia e croppa a velocità della luce, si vede su tutti i browser che ho provato (su mac/safari ha un problemino .. sigh...) alchè lo porto nel progetto che per primo dovrà utilizzarlo.
Ovviamente, non funziona piu nulla (sorvolerò sulla magra figura che ho fatto nel fare vedere al mio "collega": hey vieni a vedere che figata.. sigh :P).
Carico la foto e niente, non la salva, non la processa, non fa nulla di nulla... L'unica differenza con il test è la master page ed infatti, levandolo dalla masterpage, funziona tutto... Controllo che la riga
uploadButton.Click += new EventHandler(uploadButton_Click);
venga processata, ed in effetti così avviene, ma poi non entra mai nell'EventHandler.....
Non sono a conoscenza di bug noti per quanto riguarda l'interazione di EventHandler in Custom Control e le Master Pages... quindi ho cercato l'errore altrove.
Dopo 2 ore e mezza di ricerce, mi sono accorto che il problema era ... nella base già pronta! (ovviamente:D).
Tutte le proprietà di visualizzazione del Custom Control ( tipo DefaultImageUrl, che valorizza un controllo Image, UploadButtonText, che valorizza il Text di un Button etc) andavano ad interagire direttamente con i controlli stessi, che però venivano creati ed aggiunti nel metodo CreateChildControls().
Quindi, il furbone di controllo per essere sicuro di lavorare con i controlli già istanziati, in ogni Setter chiamava l'EnsureChildControls() . Risultato: veniva chiamato il CreateChildcontrol _prima_ del caricamento della pagina web e della pagina master.
Come probabilmente sapete, il caricamento della pagina master stravolge la struttura (e gli id....) dei controlli server, e quindi mi veniva fuori che dentro un ContentPlaceHolder con ID tipo "ctl001:contentplaceholder1", dove tutti i controlli dovrebbero avere questo prefisso, mi ritrovavo il mio controllo con id "imageControl"...
Per risolvere il problema si può cambiare il setter della proprietà in modo che interagiscano con dei campi privati e non direttamente con i controlli, e valorizzare i controlli nel CreateChildControl, oppure istanziare gli oggetti visuali nel costruttore.
In entrambi i casi, conviene lasciare assolutamente che il CreateChildControls() venga chiamto dal framework, quando è veramente necessario...