2009-05-21 11 views
7

Ho una classe di pagina base che eredita da Page. Lo chiameremo SpiffyPage.Utilizzo di un controllo utente in una classe della pagina di base

Ho anche un controllo utente chiamato SpiffyControl.

Ho quindi una pagina di aspx, ViewSpiffyStuff.aspx, che eredita da SpiffyPage.

Durante il caricamento della pagina, la classe SpiffyPage deve iniettare un SpiffyControl nella pagina di aspx.

Il problema è che SpiffyControl è un controllo utente, e per istanziare che nel codice dietro si deve accedere allo spazio dei nomi ASP, un po 'come:

ASP.controls_spiffycontrol_aspx MyControl; 

Ma SpiffyPage non è una pagina aspx, è solo una pagina di base, e come tale non posso accedere allo spazio dei nomi ASP, e quindi non posso creare un'istanza di SpiffyControl per iniettarlo.

Come posso raggiungere il mio obiettivo?

Edit:

Un punto importante è che devo avere un riferimento al tipo di controllo effettivo in modo da poter assegnare valori per alcune proprietà personalizzate. Ecco perché una funzione come LoadControl, che restituisce il controllo di tipo, non funzionerà in questo caso.

+2

È possibile utilizzare LoadControl, ma trasmetterlo. SpiffyControl spiffy = (SpiffyControl) LoadControl ("usercontrol.ascs"); – Geoff

+0

Il problema è che non riesco ad accedere al tipo SpiffyControl, quindi non posso nemmeno scriverlo - se potessi scriverlo, potrei anche semplicemente istanziarlo. –

+0

Perché non riesci ad accedere al tipo SpiffyControl? – Jonas

risposta

10

Aggiungi un baseclass al vostro SpiffyControl, come:

public class SpiffyBase : UserControl 
{ 
    public void DoIt() 
    { 
     Response.Write("DoIt"); 
    } 
} 

e poi fate la vostra SpiffyControl ereditare che baseclass, come:

public partial class SpiffyControl : SpiffyBase 

allora si dovrebbe essere in grado di farlo da una classe BasePage:

public class BasePage : Page 
{ 
    protected override void OnLoad(EventArgs e) 
    { 
     var c = Page.LoadControl("SpiffyControl.ascx") as SpiffyBase; 

     Page.Controls.Add(c); 

     c.DoIt(); 
    } 
} 
+0

Questa è davvero la soluzione più pulita/più semplice a questo problema. Una variante consiste nell'utilizzare un'interfaccia e quindi testare UserControl dopo aver caricato con: if (il controllo è ISpiffyControl) {((ISpiffyControl)). DoIt(); } – mckamey

+0

Ho avuto un problema simile e l'ho risolto in questo modo. Il motivo di questo comportamento è che il binario di asp.net è diviso in diverse dll e App_Code non vede cosa si trova nelle dll generate da aspx. – devio

4

Implementare SpiffyControl in un progetto ASP.NET Server Control separato e fare riferimento a quel progetto dall'applicazione Web. In questo modo il controllo non risiederà nello spazio dei nomi ASP, ma nello spazio dei nomi scelto e si comporterà come qualsiasi altro controllo server.

Aggiornamento: un piacevole effetto collaterale di mettere i controlli utente in un progetto separato è che diventano più disaccoppiati dall'applicazione web in quanto tale, che a sua volta tende a renderli più riutilizzabili e, a seconda del loro design, anche più verificabile.

+0

Stai dicendo di mettere il controllo utente in una DLL separata? È possibile? –

+0

Sicuro; quando si crea un nuovo progetto, nella categoria Web è possibile scegliere di creare un progetto di tipo "ASP.NET Server Control ", che fornirà un progetto in cui è possibile implementare uno (o più) controlli e che fornirà una dll come output –

+0

Ah, sì, ovviamente. Il problema è che un" controllo server "non è t lo stesso di "controllo utente". Ho un progetto di controllo server, ma sono quasi sicuro di non poter creare un controllo utente all'esterno di un progetto Web. –

1

Non sono sicuro che questo possa essere d'aiuto, ma esiste un metodo chiamato LoadControl in grado di caricare un controllo utente in modo dinamico utilizzando il nome file usercontrol o il tipo di usercontrol. Il metodo è nella classe System.Web.UI.TemplateControl.

Control userControl= LoadControl("usercontrol.ascx"); 
panelControl.Controls.Add(userControl); 
0

Anche se la base non è una pagina ASPX, si può avere ereditato dalla stessa classe quadro come se fosse:

public abstract class MyBasePage : System.Web.UI.Page 
{ 

} 
+0

Questo è quello che ho fatto - non conosco i dettagli, ma in qualche modo lo spazio dei nomi ASP semplicemente non è disponibile a meno che non scrivo in un pagina aspx attuale. –

+0

avete tutti i riferimenti necessari sulla pagina di base? Come "usare System.Web.UI.WebControls" – Geoff

+0

Sì, lo so. –

0

Supponendo SpiffyControl e SpiffyPage sono nello stesso spazio dei nomi:

Control spiffyControl = LoadControl("SpiffyControl.ascx"); 
(control as SpiffyControl).SpiffyControlProp1 = true; 
(control as SpiffyControl).SpiffyControlProp2 = "Hello, World!"; 
1

È possibile spostare lo SpiffyControl in una libreria - questo gli darà uno spazio dei nomi più preciso e ti permetterà anche di usarlo in altri progetti.Questo è un po 'complesso, però - hai già creato un UserControl, ma non funzionerà in una libreria. UserControls usa il modello codebehind - sono composti da due file, un markup e un codice. Le librerie non sembrano supportare il modello codebehind, quindi non è possibile utilizzare un UserControl. È necessario convertire tale controllo utente in un controllo web.

Creare un nuovo progetto di libreria di classi. Aprire le proprietà del progetto e impostare AssemblyName e Spazio dei nomi predefinito su SpiffyLibrary.

Ora abbiamo bisogno di convertire il tuo UserControl. Per prima cosa, crea una classe nella tua nuova libreria. Chiamalo SpiffyControl, proprio come il tuo controllo utente esistente, ma fallo ereditare da System.Web.UI.WebControls.CompositeControl.

In secondo luogo, apri il codice per il controllo utente esistente e copia tutto all'interno della classe. Quindi torna alla nuova classe e incolla tutto all'interno. Se si sta utilizzando uno degli eventi di controllo standard, potrebbe essere necessario rinominare tali funzioni per ignorare gli eventi appropriati. Ad esempio,

protected void Page_Load(object sender, EventArgs e) 
{ 
    ... 
} 

... dovrebbe diventare ...

protected override void OnLoad(EventArgs e) 
{ 
    ... 

    base.OnLoad(e); 
} 

Terzo (questa è la parte complessa) è necessario per riprodurre tutto il markup che si aveva in file di markup di SpiffyControl. Non puoi semplicemente copiarlo, ma devi sovrascrivere la funzione CreateChildControls() che è ereditata da CompositeControl. Ogni tag che hai nel markup deve essere istanziato come una variabile e aggiunto alla collezione Control della classe. Così, per esempio, se il file di markup esistente si presentava così:

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="SpiffyControl.ascx.cs" Inherits="Controls_SpiffyControl" %> 

<div id="Div1" runat="server"> 
    <asp:Label ID="TextOutput" runat="server" /> 
</div> 

... allora la vostra funzione di nuove CreateChildControls dovrebbe assomigliare a questa:

HtmlGenericControl Div1; 
Label TextLabel; 

protected override void CreateChildControls() 
{ 
    Div1 = new HtmlGenericControl("div"); 
    this.Controls.Add(Div1); 

    TextLabel = new Label(); 
    Div1.Controls.Add(TextLabel); 

    base.CreateChildControls(); 
} 

Nota che i controlli sono dichiarati come campi di classe; in questo modo, sono visibili a tutti i metodi di classe.

Una volta convertito il markup, compilare il progetto di libreria e aggiungerlo ai riferimenti per il progetto del sito web. Quindi apri il file web.config del tuo sito web e trova la sezione system.web/pages/controls. Questa sezione dovrebbe già avere un tag come questo:

<add tagPrefix="asp" namespace="System.Web.UI" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> 

Quel tag è quello che consente di utilizzare i controlli dalle librerie principali ASP. Quindi stiamo andando ad aggiungere uno uguale, per la nostra biblioteca:

<add tagPrefix="spiffy" namespace="SpiffyLibrary" assembly="SpiffyLibrary" /> 

Ora ovunque nel vostro sito, si può mettere in markup come questo:

<spiffy:SpiffyControl ID="SpiffyInstance" runat="server" /> 

... e che la volontà carica il tuo controllo web dalla tua libreria personalizzata.

0

È anche possibile definire manualmente lo spazio dei nomi di SpiffyControl. Per fare ciò, è necessario modificare sia il codebehind che il markup.

Nel codebehind, avvolgere la classe in un blocco namespace. Quindi se la tua classe era

public partial class Controls_SpiffyControl : System.Web.UI.UserControl 
{ 
    ... 
} 

... quindi cambiarlo in ...

namespace Spiffy 
{ 
    public partial class Controls_SpiffyControl : System.Web.UI.UserControl 
    { 
     ... 
    } 
} 

Quindi nel markup, regolare l'intestazione @Control. Così, se il colpo di testa @Control era

<%@ Control 
    Language="C#" 
    AutoEventWireup="true" 
    CodeFile="SpiffyControl.ascx.cs" 
    Inherits="Controls_SpiffyControl" %> 

... poi cambiarlo in ...

<%@ Control 
    Language="C#" 
    AutoEventWireup="true" 
    CodeFile="SpiffyControl.ascx.cs" 
    Inherits="Spiffy.SpiffyControl" %> 
0

Supponendo che verrà eseguita in un ambiente che supporta la riflessione si potrebbe utilizzare questi metodi.

private void SetValue(Control control, string propertyName, object value) 
{ 
    Type type = control.GetType(); 
    PropertyInfo property = type.GetProperty(propertyName); 
    property.SetValue(control, value, null); 
} 
private object GetValue(Control control, string propertyName) 
{ 
    Type type = control.GetType(); 
    PropertyInfo property = type.GetProperty(propertyName); 
    return property.GetValue(control, null); 
} 

E chiamare in questo modo:

 Control control = this.LoadControl("~/SpiffyControl.ascx"); 
    string propertyName = "Custom1"; 
    object value = "Value"; 

    SetValue(control, propertyName, value); 

Se viene chiamato un sacco si potrebbe desiderare di memorizzare nella cache le informazioni sul tipo.

Si potrebbe anche prendere in considerazione la creazione di un'interfaccia ISpiffyControl nell'assieme in cui si trova SpiffyPage, quindi è necessario che il controllo utente lo implementa.

2

Sei ragazzi scherzando, io so che ASP.NET WebForms è stata un'esperienza dolorosa, ma ha nessuno sentito dell'attributo ClassName, cioè

<%@ Control ClassName="SpiffyControl" Language="C#" AutoEventWireup="true" CodeFile="SpiffyControl.ascx.cs" Inherits="Controls_SpiffyControl" %> 

Così, l'esempio originale:

SpiffyControl spiffy = (SpiffyControl)LoadControl("~spiffy.ascx"); 
0

È stato modificato, ma un'interfaccia dovrebbe funzionare. Fare ISpiffyControl con qualsiasi soci/metodi, la sua attuazione nel SpiffyControl.ascx.vb e farlo nel SpiffyPage:

Protected Overrides Sub OnLoad(ByVal e As System.EventArgs) 
    MyBase.OnLoad(e) 
    Dim page As New Page 
    Dim path As String = request.ApplicationPath 
    Dim control as UI.Control = page.LoadControl(String.Format _ 
     ("{0}/pathToUserControl/{1}.ascx", path, controlName)) 
    Dim sc As ISpiffyControl = CType(control, ISpiffyControl) 
    sc.DoSomethingSpecial() 
    Me.Controls.Add(sc) 
End Sub 
0

Se leggo correttamente, il manifesto originale aveva il problema in cui non può accedere al Tipo della classe base da cui la pagina padre ha derivato nel suo UserControl, non il contrario. Accade solo di avere lo stesso problema.

Nel mio caso tutte le pagine del mio progetto ereditano dalla stessa base, quindi non mi preoccupo del fatto che il mio controllo utente abbia una conoscenza della classe base della pagina. Scuse agli architetti.

Tuttavia, ho risolto il problema con una combinazione di 1) utilizzando una classe base per il controllo utente e 2) utilizzando uno spazio dei nomi comune. Ciò ha permesso la visibilità di cui avevo bisogno, poiché per qualche motivo la classe base del controllo utente non poteva ancora vedere il tipo di classe base della classe base delle pagine.

In ogni caso, ho pensato di condividere i miei risultati nel caso in cui aiutassero qualcun altro in futuro.

HTH.

Problemi correlati