2009-05-21 7 views
7

J'ai une classe de page de base qui hérite de Page. Nous l'appellerons SpiffyPage. J'ai également un contrôle utilisateur appelé SpiffyControl. J'ai alors une page aspx, ViewSpiffyStuff.aspx, qui hérite de SpiffyPage.Utilisation d'un contrôle utilisateur dans une classe de pages de base

Lors du chargement de la page, la classe SpiffyPage est censée injecter un SpiffyControl dans la page aspx.

Le problème est que SpiffyControl est un contrôle utilisateur et à instancier que dans le code derrière on doit accéder à l'espace de noms ASP, un peu comme:

ASP.controls_spiffycontrol_aspx MyControl; 

Mais SpiffyPage n'est pas une page ASPX, C'est juste une page de base, et en tant que tel, je ne peux pas accéder à l'espace de noms ASP, et je ne peux donc pas instancier un SpiffyControl pour l'injecter.

Comment puis-je atteindre mon objectif?

Edit:

Un point important est que je dois avoir une référence au type de contrôle réel pour que je puisse attribuer des valeurs à certaines propriétés personnalisées. C'est pourquoi une fonction comme LoadControl, qui renvoie le type Control, ne fonctionnera pas dans ce cas.

+2

Vous pouvez utiliser LoadControl, mais le convertir. SpiffyControl spiffy = (SpiffyControl) LoadControl ("usercontrol.ascs"); – Geoff

+0

Le problème est que je ne peux pas accéder au type SpiffyControl, donc je ne peux pas non plus le lancer - si je pouvais le lancer, je pourrais simplement l'instancier. –

+0

Pourquoi ne pouvez-vous pas accéder au type SpiffyControl? – Jonas

Répondre

10

Ajouter un baseclass à votre SpiffyControl, comme:

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

puis vous faites votre SpiffyControl hériteront de cette baseclass, comme:

public partial class SpiffyControl : SpiffyBase 

alors vous devriez être en mesure de le faire d'une 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

Celui-ci est vraiment la solution la plus propre/la plus simple à ce problème. Une variante consiste à utiliser une interface, puis à tester UserControl après le chargement de: if (control is ISpiffyControl) {((ISpiffyControl)). DoIt(); } – mckamey

+0

J'ai eu un problème similaire, et l'ai résolu de cette façon. La raison de ce comportement est que le binaire asp.net est divisé en plusieurs dll, et App_Code ne voit pas ce qui se trouve dans la DLL générée par aspx. – devio

4

Je voudrais implémenter SpiffyControl dans un projet de contrôle serveur ASP.NET distinct et référencer ce projet à partir de l'application Web. De cette façon, le contrôle ne réside pas dans l'espace de noms ASP, mais dans l'espace de noms de votre choix et se comporte comme n'importe quel autre contrôle serveur.

Mise à jour: un bon effet secondaire de placer les contrôles utilisateur dans un projet séparé est qu'ils sont plus découplés de l'application web en tant que telle, ce qui les rend plus réutilisables et, selon leur conception, plus testable.

+0

Vous dites mettre le contrôle utilisateur dans une DLL séparée? Est-ce possible? –

+0

Bien sûr; Lorsque vous créez un nouveau projet, dans la catégorie Web, vous pouvez choisir de créer un projet de type "ASP".NET Server Control ", qui vous donnera un projet où vous pouvez implémenter un (ou plusieurs) contrôles, et qui donnera une dll en sortie –

+0

Ah, oui, bien sûr, le problème est qu'un" serveur de contrôle "n'est pas –

1

Je ne sais pas si cela vous aidera, mais il existe une méthode appelée LoadControl qui peut charger dynamiquement un contrôle utilisateur en utilisant le nom de fichier usercontrol ou le type de usercontrol. La méthode est dans la classe System.Web.UI.TemplateControl.

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

Même si votre base n'est pas une page ASPX, vous pouvez l'avoir hérité de la même classe de cadre comme si elle était:

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

} 
+0

C'est ce que j'ai fait - je ne connais pas les détails, mais en quelque sorte l'espace de noms ASP n'est tout simplement pas disponible sauf si j'écris dans un page aspx réelle. –

+0

avez-vous toutes les références dont vous avez besoin sur la page de base? Comme "using System.Web.UI.WebControls" – Geoff

+0

Ouais, je suis sûr. –

0

Si l'on suppose SpiffyControl et SpiffyPage sont dans le même espace:

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

Vous pouvez déplacer votre SpiffyControl dans une bibliothèque - ce lui donnera un espace de noms plus précis et vous permettra également de l'utiliser dans d'autres projets.C'est un peu complexe, cependant - vous avez déjà un UserControl, mais cela ne fonctionnera pas dans une bibliothèque. UserControls utilise le modèle codebehind - ils sont composés de deux fichiers, un balisage et un code. Les bibliothèques ne semblent pas prendre en charge le modèle codebehind, donc vous ne pouvez pas utiliser UserControl. Vous devez convertir ce contrôle utilisateur en contrôle Web.

Créez un nouveau projet de bibliothèque de classes. Ouvrez les propriétés du projet et définissez AssemblyName et Default Namespace à SpiffyLibrary.

Maintenant, nous devons convertir votre UserControl. Commencez par créer une classe dans votre nouvelle bibliothèque. Appelez-le SpiffyControl, tout comme votre contrôle utilisateur existant, mais faites-le hériter de System.Web.UI.WebControls.CompositeControl. Deuxièmement, ouvrez le code de votre contrôle utilisateur existant et copiez tout ce qui se trouve à l'intérieur de la classe. Puis revenez à la nouvelle classe et collez tout à l'intérieur. Si vous utilisez l'un des événements de contrôle standard, vous devrez peut-être renommer ces fonctions pour remplacer les événements appropriés. Par exemple,

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

... doit devenir ...

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

    base.OnLoad(e); 
} 

troisième (ce qui est la partie complexe), vous devez reproduire toutes les balises que vous aviez dans le fichier de balisage de SpiffyControl. Vous ne pouvez pas simplement le copier - à la place, vous devez remplacer la fonction CreateChildControls() héritée de CompositeControl. Chaque balise que vous avez dans le balisage doit être instanciée comme une variable et ajoutée à la collection Controls de la classe. Ainsi, par exemple, si votre fichier de balisage existant ressemblait à ceci:

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

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

... alors votre nouvelle fonction CreateChildControls devrait ressembler à ceci:

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(); 
} 

Notez que les contrôles sont déclarés comme des champs de classe; De cette façon, ils sont visibles pour toutes les méthodes de classe. Une fois votre balisage converti, compilez le projet de bibliothèque et ajoutez-le aux références de votre projet de site Web. Ensuite, ouvrez le fichier web.config de votre site Web et recherchez la section system.web/pages/controls. Cette section devrait déjà avoir une balise comme ceci:

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

Cette balise est ce qui vous permet d'utiliser les contrôles des bibliothèques centrales ASP. Nous allons donc ajouter un peu comme ça, pour notre bibliothèque:

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

maintenant partout dans votre site, vous pouvez mettre dans le balisage comme ceci:

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

... et qui chargez votre contrôle Web à partir de votre bibliothèque personnalisée.

0

Vous pouvez également définir l'espace de noms de votre SpiffyControl manuellement. Pour ce faire, vous devez modifier le codebehind et le balisage.

Dans le codebehind, enveloppez votre classe dans un bloc d'espace de noms. Donc, si votre classe était

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

... alors changez-le en ...

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

Ensuite, dans le balisage, réglez votre en-tête @Control. Donc, si votre tête de @Control était

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

... puis changer pour ...

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

En supposant que vous exécuterez dans un environnement qui prend en charge la réflexion que vous pouvez utiliser ces méthodes.

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); 
} 

Et l'appeler comme ceci:

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

    SetValue(control, propertyName, value); 

Si elle est appelée beaucoup vous pouvez mettre en cache les informations de type.

Vous pouvez également envisager de créer une interface ISpiffyControl dans l'assemblage dans lequel SpiffyPage est installé, puis demandez à votre contrôle utilisateur de l'implémenter.

2

des gars vous moquez de moi, je sais que ASP.NET WebForms était une expérience douloureuse mais a personne entendu parler de l'attribut ClassName, à savoir

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

Ainsi, l'exemple d'origine:

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

Il a été touché, mais une interface devrait fonctionner. Faire ISpiffyControl avec quelles que soient les membres/méthodes, mettre en œuvre dans le SpiffyControl.ascx.vb et le faire dans le 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

Si je lis bien cela, l'affiche originale avait le problème dans lequel il ne peut pas accéder à la Type de la classe de base à partir de laquelle la page parente a dérivé dans son UserControl, et non l'inverse. C'est comme ça que j'ai eu le même problème.

Dans mon cas, toutes les pages de mon projet héritent de la même base, donc je ne m'inquiète pas du fait que mon contrôle utilisateur a une connaissance de la classe de base de la page. Toutes mes excuses aux architectes.

Cependant, j'ai résolu le problème avec une combinaison de 1) en utilisant une classe de base pour mon contrôle utilisateur, et 2) en utilisant un espace de noms commun. Cela a permis la visibilité dont j'avais besoin, car pour une raison quelconque, la classe de base du contrôle utilisateur ne pouvait toujours pas voir le type de classe de base de la classe de base des pages.

De toute façon, je pensais juste partager mes résultats au cas où ils aideraient quelqu'un d'autre dans le futur.

HTH.

Questions connexes