LoadControl in static/shared function
Asked Answered
B

4

5

Anyone know how I can dynamically load a control inside of a shared/static function? The function itself is inside of a mustinherit/abstract class. (It's an ASP.NET project in VB) I want to do something like this:
VB:

    Public Shared Function GetWidget(ByVal name As WidgetName) As Control
        Select Case name
            Case WidgetName.Name1
                Return LoadControl("~/Control1.ascx")
            Case WidgetName.Name2
                Return LoadControl("~/Control2.ascx")
            Case WidgetName.Name3
                Return LoadControl("~/Control3.ascx")
        End Select
    End Function

my C# is a little rusty, so this might have some syntax errors:

Public Static Control GetWidget(WidgetName name)  
{  
    switch (name)  
    {  
        Case WidgetName.Name1:  
            return LoadControl("~/Control1.ascx");  
            break;  
        Case WidgetName.Name2:  
            return LoadControl("~/Control2.ascx");  
            break;  
        Case WidgetName.Name3:  
            return LoadControl("~/Control3.ascx");  
            break;  
    }  
}  

(Where WidgetName is an enumerator.)

I'm getting "Cannot refer to an instance member of a class from within a shared method or shared member initializer without an explicit instance of the class.", but I don't understand this error. I understand what it means, I just don't understand why calling LoadControl isn't seen by the compiler as being an explicit instance of the class. What's not explicit about using LoadControl to create a new control from a file? I tried creating a new user control and initializing it, then setting it to a different control with LoadControl to no avail. I also don't want to do a DirectCast because I'm trying to put this in a shared, mustinheret (abstract) class, which therefore doesn't have an .aspx file to write in a <%@ Reference Control="~/SomeControlPath.ascx" %>, so the class name is unavailable.

What I'm trying to do is write a static function that takes some value and returns a control based only on that control's source file location. The end result is a user-modifiable list of controls. They get a column of controls that they freely add, remove, or reorder based on a static list of available child controls that I specify. I'm not married to this approach; it might be really wrong in more ways than one.

yeah, I know the static strings being there is code smell, it doesn't actually look like that; it's a simplification for the sake of asking the question.

C#, VB, or plain English explanations all welcome.

Benn answered 30/12, 2009 at 17:17 Comment(0)
C
0

Is it because LoadControl can't be returned from your class? Can you try this instead...

    Protected Static string GetWidget(WidgetName name)  
    {  
        switch (name)  
        {  
            Case WidgetName.Name1:  
                return "~/Control1.ascx";  
                break;  
            Case WidgetName.Name2:  
                return "~/Control2.ascx";  
                break;  
            Case WidgetName.Name3:  
                return"~/Control3.ascx";  
                break;  
      }  
 } 

and call the method like

... = LoadControl(GetWidget(name));

I suspect that the other alternative is to cast the control

Control c;
...
Case ...
   c = (ControlName)LoadControl("~/Control1/.ascx");
   break;
...
return c;

However the calling code would still need to cast it back to its type...

Contempt answered 30/12, 2009 at 17:26 Comment(5)
It is not about what is getting returned...it is that you cannot call the LoadControl method from inside the static method...because there is no instance.Biform
No worries, been there! Grab a coffee and stay off the beer :) :)Contempt
@Biform - You are correct which is why I suggested an alternative.Contempt
@Rippo...your casting solution will not work...because you cannot call LoadControl() from inside the static method.Biform
haha I didn't drink last night, I've just been going at it for a few hours non-stop on a very finicky project I inherited, so I'm a little frazzled ;)Benn
B
11

Actually, you can do it like this (it works):

UserControl tmp0 = new UserControl();
Control ctl = tmp0.LoadControl("MyControl.ascx");
Barbirolli answered 24/7, 2011 at 21:45 Comment(0)
B
1

LoadControl is an instance method on the TemplateControl class which the Page class inherits from, and you do not have an instance of the Page class inside your static method (there is no this object because it is a static method).

Biform answered 30/12, 2009 at 17:32 Comment(3)
ah, thank you for the technicals, that's helpful to know. I understand the error now. Up until now I hadn't really thought much about the context of the LoadControl definition, I just took it for granted and used it.Benn
In your intellisense menu...LoadControl should not have come up as an option in your static method..Biform
yeah, it doesn't. I wrote the body of the method with the signature specifying it as an instance method, then decided it would be an easier read if it was shared so I changed the signature, which is when I started to see the error and didn't quite understand it.Benn
V
1

All good information here, but I'm surprised that no one has used it to make the leap to an actual solution to the original question:

Public Shared Function GetWidget(ByVal name As WidgetName,
                                 ByVal onTemplate As TemplateControl) As Control
    Select Case name
        Case WidgetName.Name1
            Return onTemplate.LoadControl("~/Control1.ascx")
        Case WidgetName.Name2
            Return onTemplate.LoadControl("~/Control2.ascx")
        Case WidgetName.Name3
            Return onTemplate.LoadControl("~/Control3.ascx")
    End Select
End Function

I tested this solution and it woks.

I like it better than Rippo's solution because it prevents the caller from having to worry about the LoadControl details. And this is definitely a better solution if there is more work to be done to the resulting control other than simply returning it.

I would not have reached this solution without CSharpAtl's answer, though, because I (stupidly) did not realize that LoadControl is a method on TemplateControl. Like the original poster, I was very confused about why I was getting the same error. I could not understand why it would not be OK to load a control in a shared method, and in fact, it is OK if you know how to call LoadControl in this context!

Brian

Virnelli answered 9/11, 2010 at 15:2 Comment(0)
C
0

Is it because LoadControl can't be returned from your class? Can you try this instead...

    Protected Static string GetWidget(WidgetName name)  
    {  
        switch (name)  
        {  
            Case WidgetName.Name1:  
                return "~/Control1.ascx";  
                break;  
            Case WidgetName.Name2:  
                return "~/Control2.ascx";  
                break;  
            Case WidgetName.Name3:  
                return"~/Control3.ascx";  
                break;  
      }  
 } 

and call the method like

... = LoadControl(GetWidget(name));

I suspect that the other alternative is to cast the control

Control c;
...
Case ...
   c = (ControlName)LoadControl("~/Control1/.ascx");
   break;
...
return c;

However the calling code would still need to cast it back to its type...

Contempt answered 30/12, 2009 at 17:26 Comment(5)
It is not about what is getting returned...it is that you cannot call the LoadControl method from inside the static method...because there is no instance.Biform
No worries, been there! Grab a coffee and stay off the beer :) :)Contempt
@Biform - You are correct which is why I suggested an alternative.Contempt
@Rippo...your casting solution will not work...because you cannot call LoadControl() from inside the static method.Biform
haha I didn't drink last night, I've just been going at it for a few hours non-stop on a very finicky project I inherited, so I'm a little frazzled ;)Benn

© 2022 - 2024 — McMap. All rights reserved.