Inizializzazione del controllo figlio in composito personalizzato in ASP.NET
-
02-07-2019 - |
Domanda
Parte della serie di controlli a cui sto lavorando ovviamente mi coinvolge nel raggruppare alcuni di essi nei compositi. Sto rapidamente iniziando a sapere che questo prende in considerazione (è tutto nuovo per me!) :)
Fondamentalmente ho un controllo StyledWindow
, che è essenzialmente un Pannello
glorificato con la possibilità di fare altri bit (come aggiungere bordi ecc.).
Ecco il codice che crea un'istanza dei controlli figlio al suo interno. Fino a questo punto sembra aver funzionato correttamente con banali controlli statici:
protected override void CreateChildControls()
{
_panel = new Panel();
if (_editable != null)
_editable.InstantiateIn(_panel);
_regions = new List<IAttributeAccessor>();
_regions.Add(_panel);
}
I problemi sono arrivati ??oggi quando ho provato a annidare un controllo più complesso al suo interno. Questo controllo utilizza un riferimento alla pagina poiché inserisce JavaScript per renderlo un po 'più scattante e reattivo (il RegisterClientScriptBlock
è l'unica ragione per cui ho bisogno del riferimento della pagina).
Ora, ciò stava causando " oggetto null " errori, ma l'ho localizzato nel metodo render, che ovviamente stava cercando di chiamare il metodo contro l'oggetto [null] Page
.
Ciò che mi confonde è che il controllo funziona bene come standalone, ma quando inserito in StyledWindow
tutto va terribilmente storto!
Quindi, sembra che mi manchi qualcosa nel mio StyledWindow
o ChildControl
. Qualche idea?
Aggiornamento
Come Brad Wilson ha giustamente sottolineato , non vedi i controlli aggiunti alla raccolta Controls
. Questo è lo scopo del _panel
, questo era lì per gestirlo per me, fondamentalmente quindi sovrascrivere Controls
(l'ho preso da una guida da qualche parte):
Panel _panel; // Sub-Control to store the "Content".
public override ControlCollection Controls
{
get
{
EnsureChildControls();
return _panel.Controls;
}
}
Spero che aiuti a chiarire le cose. Scuse.
Aggiornamento dopo Risposta di Longhorn213
Bene, ho giocato un po 'con il controllo, inserendone uno all'interno del composito e uno all'esterno. Ho quindi ottenuto lo stato di Page all'evento principale dell'evento nel ciclo di vita del controllo e l'ho visualizzato nella pagina.
Il sistema autonomo funziona correttamente e la pagina viene avviata come previsto. Tuttavia, quello nidificato nel composito è diverso. È l'evento OnLoad
che non viene sparato affatto! Quindi suppongo che Brad abbia probabilmente ragione nel non impostare correttamente la gerarchia dei controlli, qualcuno può offrire qualche consiglio su cosa mi sto perdendo? Il metodo Panel non è abbastanza? (beh, ovviamente non è vero ?!): D
Grazie per il vostro aiuto ragazzi, apprezzato :)
Soluzione 3
risolto!
Bene, ero determinato a risolverlo oggi! Ecco i miei pensieri:
- Ho pensato che l'uso di
Panel
fosse un po 'un trucco, quindi dovrei rimuoverlo e scoprire come è realmente fatto. - Non volevo fare qualcosa come
MyCtl.Controls [0] .Controls
per accedere ai controlli aggiunti al composito. - Volevo che la dannata cosa funzionasse!
Quindi, ho cercato e colpito MSDN , questo articolo è stato DAVVERO utile (vale a dire quasi copia e incolla, e spiegato bene - qualcosa che MSDN è tradizionalmente cattivo). Nizza!
Quindi, ho strappato l'uso di Panel
e ho praticamente seguito l'artcle e l'ho preso come vangelo, prendendo appunti mentre andavo.
Ecco quello che ho adesso:
- Ho imparato che stavo usando il termine sbagliato. Avrei dovuto chiamarlo Controllo basato su modelli . Mentre i controlli basati su modelli sono tecnicamente composti, esiste una differenza netta. I controlli basati su modelli possono definire l'interfaccia per gli elementi che vengono aggiunti ad essi.
- I controlli basati su modelli sono molto potenti e in realtà sono piuttosto veloci e facili da configurare una volta che hai la testa intorno a loro!
- Giocherò un po 'di più con il supporto del designer per assicurarmi di averlo compreso appieno, quindi ottenere un post sul blog :)
- A " Template " controllo viene utilizzato per specificare l'interfaccia per i dati basati su modelli.
Ad esempio, ecco il markup ASPX per un controllo basato su modelli:
<cc1:TemplatedControl ID="MyCtl" runat="server">
<Template>
<!-- Templated Content Goes Here -->
</Template>
</cc1:TemplatedControl>
Ecco il codice che ho ora
public class DummyWebControl : WebControl
{
// Acts as the surrogate for the templated controls.
// This is essentially the "interface" for the templated data.
}
In TemplateControl.cs ...
ITemplate _template;
// Surrogate to hold the controls instantiated from
// within the template.
DummyWebControl _owner;
protected override void CreateChildControls()
{
// Note we are calling base.Controls here
// (you will see why in a min).
base.Controls.Clear();
_owner = new DummyWebControl();
// Load the Template Content
ITemplate template = _template;
if (template == null)
template = new StyledWindowDefaultTemplate();
template.InstantiateIn(_owner);
base.Controls.Add(_owner);
ChildControlsCreated = true;
}
Quindi, per fornire un facile accesso ai controlli dell'oggetto [Surrogate]:
(ecco perché dovevamo cancellare / aggiungere alla base.Controls)
public override ControlCollection Controls
{
get
{
EnsureChildControls();
return _owner.Controls;
}
}
E questo è abbastanza, facile quando sai come! :)
Avanti: Supporto per la regione del tempo di progettazione!
Altri suggerimenti
Non ti vedo aggiungere i tuoi controlli alla raccolta Controlli da nessuna parte, il che spiegherebbe perché non possono accedere alla Pagina (dal momento che non sono mai stati ufficialmente inseriti nella pagina).
Ho sempre inserito le chiamate JavaScript nella funzione OnLoad. Come sotto.
protected override void OnLoad(EventArgs e)
{
// Do something to get the script
string script = GetScript();
this.Page.ClientScript.RegisterClientScriptBlock(this.Page.GetType(), "SomeJavaScriptName", script);
// Could also use this function to determine if the script has been register. i.e. more than 1 of the controls exists
this.Page.ClientScript.IsClientScriptBlockRegistered("SomeJavaScriptName");
base.OnLoad(e);
}
Se vuoi ancora eseguire il rendering, puoi semplicemente scrivere lo script nella risposta. Il che è ciò che fa RegisterScriptBlock, inserisce semplicemente lo script nella pagina.
Bene, ho iniziato a suonare e ho pensato che ci fosse qualcosa di sbagliato nella mia istanza di controllo, dato che Longhorn aveva ragione, dovrei essere in grado di creare riferimenti di script su OnLoad
(e non potevo) e Brad aveva ragione nel ritenere che la mia gerarchia Controls
fosse mantenuta aggiungendo alla raccolta Controls
del composito.
Quindi, avevo due cose qui:
- Avevo scavalcato l'accessorio proprietà
Controls
per il composito per restituire la raccolta Controls di questoPannello
poiché non voglio andarectl.Controls [ 0] .Controls [0]
per ottenere il controllo effettivo che desidero. L'ho rimosso, ma devo ordinarlo. - Non avevo aggiunto il
pannello
alla raccoltaControls
, ora l'ho fatto.
Quindi, ora funziona, tuttavia, come posso ottenere la proprietà Controls
per il composito per restituire gli elementi nel Pannello
, piuttosto che < codice> Pannello stesso?