Loading User Controls (ascx) from other User Controls - c#

I have a UserControl (ascx) that, depending on the user's credentials, will load another UserControl (ascx). Currently the control to be loaded, contains a special navigation menu.
I am using this code:
UserControl jmNav =
(UserControl)Page.LoadControl("~/controls/client/jmNavigation.ascx");
Then, after some more code, I'm telling it to load, like this:
SBarTopWelcome.Controls.Add(jmNav);
The problem is, that I'm getting an "object reference not set to instance of an object" error.
Yes, the path is correct - as I tried it like this, as well (in all variations):
UserControl jmNav = (UserControl)Page.LoadControl("/client/jmNavigation.ascx");
This one (and its variants) tells me it doesn't exist.
So! Any thoughts?

One helpful solution is to add <%# Register %> to your parent control. Yes, I know it's in your parent page, but it should also be in your control.
If you do this, you should be able to Strongly-Type your control. For example, a control with a class name of MyControl would be:
MyControl controlVar = (MyControl)this.LoadControl("MyControl.aspx");
If you are able to get the stronly-defined variable, you should have no problems.

Inside SideBar.ascx add a place holder named SideBarTopWelcomePlaceHolder.
<asp:PlaceHolder ID="SideBarTopWelcomePlaceHolder" runat="server"/>
Then load jmNavigation UserControl to SideBarTopWelcomePlaceHolder like this.
Control jmNav =
Control Page.LoadControl("~/controls/client/jmNavigation.ascx");
SideBarTopWelcomePlaceHolder.Add(jmNav);

HA! I'm such a DORK! I was declaring the "SideBarWelcome" within a control like this:
public Control sideBarTopWelcome
{
get { return Page.FindControl("SideBarTopWelcome"); }
}
When I should have done it like this:
public Control sideBarTopWelcome
{
get { return FindControl("SideBarTopWelcome"); }
}
Without Page. Thank you anyway, guys. I appreciate it.

Related

Unable To Render Control To Placeholder

The following code will not add a control to an aspx placeholder:
var control = new ASCXControl { ID="searchFilters", Filters = filters };
var placeholder = Utility.FindControlRecursive(Page, "rightColumnSearchFilters") as PlaceHolder;
if(placeholder != null){
placeholder.Controls.Add(control);
placeholder.Visible = true;
}
When debugging, the placeholder is found and the control shows as added to the placeholder controls collection after entering the block, but yet I see nothing render into the placeholder on the page.
I currently need to pass variables to the control in order to find the filters I need to display. Although I don't like passing variables between controls, I don't see any other way.
What am I missing would make the control not render? Is there a better way to do this?
EDIT:
I am trying to get the HTML inside of the ascx to render. I am able to get the Filters parameters inside the Page_Load on the control.
This may or may not be the whole problem, but usually trying to instantiate a UserControl the way you're doing it leads to problems. You should do it using the LoadControl(path) method of the Page class:
ASCXControl ctl = (ASCXControl) LoadControl("path");
I'm not 100% sure, but I think that if you just instantiate it like an ordinary class/control, you wind up not running all the event handlers (such as Load) that you usually would.

Access Controls from UserControls in ASPX page

How to Access Controls from UserControls in ASPX page?
For example:
I want to access gridview which is in usercontrol on ASPX page.
Please help me.
Try this :
GridView GridView1 = (GridView)WebUserControl1.FindControl("GridView1");
Where WebUserControl1 is ID of use control on .aspx page.
Hope this helps..
The best way is to provide properties in your UserControl that you can access.
For example:
public GridView UserGrid
{
get
{
return GridView1;
}
}
But the question is why you need this.
Rule of thumb: Only expose as few as possible. On that way your code will be most robust and readable. So it would e.g. better to expose it's DataSource rather than the complete GridView.
On the other hand, if you want your page to react on events in your UserControl, it should provide custom events(e.g. UserDeleted) that your page then can handle.
Page-UserControl-Commmunication
Because the controls now nothing about eachother at the same level, you have to use the parent page to get it. Try this logic:
Create a property referring to your parent page (the page your control usually is in (might be different because of layering of controls)
Create a property on your page referring to the usercontrol the grid is in, or link to that grid directly.
page.aspx
public UserControl UserGridControl
{
get;
set;
}
userControl.ascx
public Page ParentPage
{
get;
set;
}
Example call:
Instantiate the properties first. After that, use the following statement to access anything from that control (as an example I used Foo() here, to use as a dummy method, but it seems it was unclear to someone):
otherControl.ascx:
this.ParentPage.UserGridControl.Foo();
EDIT: Want to have a direct code example to be able do it from the page only? See Tim Schmelters answer. If you need a way to call the grid from another user control as well. Use mine.

Dynamically adding controls to a Templated User Control?

A few weeks back I created a Templated User Control, for the most part based on the example here:
http://msdn.microsoft.com/en-us/library/36574bf6(v=VS.90).aspx
The difference is that I did not implement the "MessageContainer" class as I wanted just an empty template that I could add whatever controls I wanted to at design time.
This TUC has been working great, but I ran into a scenario I hadn't anticipated when I created the thing. The need to dynamically add this TUC to a page, which means that I would need to dynamically add the controls within the template of the TUC as well.
I found another example here on how to dynamically create a Template and add it to the Templated Control:
http://msdn.microsoft.com/en-us/library/y0h809ak(v=vs.71).aspx
This second example article discusses only the "DataList, Repeater, and DataGrid controls" but I figure since I am using the ITemplate interface here, it should be the same thing.
However, I am unable to get this to work, I keep getting an "Object reference not set to an instance of an object." error when I attempt to populate the TUC.
Here's what I am doing....
Like the example above I created an ITemplate class:
public class XPCTemplate : ITemplate
{
private readonly Control _control;
public XPCTemplate(Control control)
{
_control = control;
}
public void InstantiateIn(Control container)
{
container.Controls.Add(_control);
}
}
Then, in the test page code-behind I attempt to load up and display the TUC dynamically:
ExpandCollapseRegion xpcRegion; // The Templated User Control
protected void Page_Load(object sender, EventArgs e)
{
PlaceHolder ph;
// .... code here to dynamically create some labels, textboxes, etc. ....
// Create an instance of the TUC
xpcRegion = new ExpandCollapseRegion();
// Pass into the TUC's template the controls dynamically created above
xpcRegion.LayoutTemplate = new XPCTemplate(ph);
// add the dynamic TUC to the page
phDynamicUC.Controls.Add(xpcRegion);
phDynamicUC.Controls.Add(new LiteralControl("<br />"));
}
Test page HTML Source:
<body>
<form id="form1" runat="server">
<div>
Dynamically Loading User Control
<br />
<asp:PlaceHolder ID="phDynamicUC" runat="server" />
</div>
</form>
</body>
When I run the page, I get the "Object reference not set to an instance of an object" error on the "container.Controls.Add(_control);" line of the XPCTemplate class. When I debug the test page and TUC control, the code of the TUC receives the XPCTemplate into its LayoutTemplate during the TUC's Page_Init() method, but when the InstantiateIn() event back in the XPCTemplate fires immediately afterwards, the "container" argument is NULL.
I'm not sure why this is happening, it's like the InstantiateIn() method of the XPCTemplate class is trying to actually set the PlaceHolder control within the TUC rather than just passing the contents. Maybe this is supposed to be the way and I am missing something on the TUC side to allow this behavior?
This is the first TUC I have created and likewise the first time trying to dynamically fill/load it, so I am sure I am missing something needed to accomplish this. Any help is greatly appreciated.
-- Andrew
Found the solution to the problem, which was how I was loading the TUC.
Incorrect:
xpcRegion = new ExpandCollapseRegion();
Correct:
xpcRegion = (ExpandCollapseRegion)LoadControl("ExpandCollapseRegion.ascx");
Making this simple change took care of the problem. Also, found that I could forego the need for a custom ITemplate class by using the CompiledTemplateBuilder() method. Really simplifies the code.
-- Andrew
I believe the problem is that you haven't instantiated your PlaceHolder ph that you are passing into your template. So, the line it is complaining on is because it can't add the control to the PlaceHolder because it is null/nothing.
Also, I believe you're going to need to put your placeholder somewhere. Otherwise, you're adding items to a container that is never added to the page.

calling a method on the parent page from a user control

I am using a user control that I created (just a .cs file not an .ascx file), that does some magic and depending on a value generated by the control, I need it to do something on the parent page that is 'hosting' the control. It needs to call a method under certain circumstances (method is on the parent control).
the control is placed on the parent page like so:
<customtag:MyControl ID="something" runat="server" />
I'm dynamically creating buttons etc on the control itself but when a button is clicked, let's say for example that there's a text box on the control and if the value of the textbox is "bob" it needs to call a method on the page that's housing the control...how can I accomplish this?
You could do what casperOne suggested, but I wouldn't advise it. This is tightly coupling your user control to your parent page, which kind of defeats the purpose of a user control.
Personally, I'd add an event to the user control (say, ButtonClicked) that the parent page can handle. In the event handler in your parent, deal with the event however you see fit. This way you can plug the user control into a different page at a later date and not have to worry about logic in the user control that requires a specific kind of parent page.
You should be able to get the Page hosting the control through the Parent property. However, that's going to be returned to you as a Control. You have to cast it to the type of your page in order to access any methods on the page which you have defined.
I think that casperOne is on the right track, but you need to go a step further. I'm giong to make the assumption that this user control will be used on more then on page. (I normally write VB.Net, sorry if my C# is malformed)
Make a base page class (you can store it in your App_Code directory or in a project):
public class PageToInheritFrom : System.Web.UI.Page {
public void SpecialFunction() {
}
}
Now make sure that all of your pages inherit from this page in your code behind file:
public partial class _Default : PageToInheritFrom {
}
Now in your user control you know what the page type is and can call
((PageToInheritFrom)this.Page).SpecialFunction();

ASP.Net: User control with content area, it's clearly possible but I need some details

I have seen two suggestions for my original question about whether it is possible to define a content area inside a user control and there are some helpful suggestions i.e.
Passing in content to ASP.NET user control
and
ASP.NET User Control inner content
Now, I like the theory of the latter better than the former just for aesthetic reasons. It seems to make more sense to me but the example given uses two variables content and templateContent that the answerer has not defined in their example code. Without these details I have found that the example does not work. I guess they are properties of the control? Or some such?
EDIT - DETAILS: What I am trying to do
I have need of an ASP.Net user control that conceals some content in a panel inside a placeholder and asks for the input of a code in a visible panel.
Essentially the user will put their code into the provided textbox in Panel A and submit it, it will be checked and, if it is valid, panel B and the locked content will be displayed.
I have done a test where the content was hard coded into panel B but as soon as I need to make the content a generic input it fails. If it were just text or somesuch then I could make it a property of the control, but as it is, in fact, another User Control I am having some difficulty getting this into the "hidden" panel.
Any other workable solutions are also welcome.
EDIT NOTE: The solution I'm trying to implement this in 2.0 I did find a 3.5 solution which I cannot use.
The former example seems workable but I'd prefer to go with the latter if someone could fill in the blanks for me.
Thanks.
Okay, so this is disturbingly easy but many of the tutorials on the web that talk about this kind of thing push to do extravagant things that require the control to parse ListItems or such.
So this solution is purely so that you can build a control that, for whatever reason, has a placeholder in it that could have anything inside it (kind of like a content area on a Master page). In this instance it happens to be because the Panel containing the placeholder is hidden until appropriate input actions have taken place in another panel.
First, you need to add this:
[ParseChildren(true,"Content")]
[PersistChildren(false)]
just above the part of the control which looks like this:
public partial class MyControl : System.Web.UI.UserControl
then in the control scoped declarations at the head of the control you want to declare thus:
private Control _content;
[PersistenceMode(PersistenceMode.InnerProperty)]
public Control Content { get { return _content; } set { _content = value; } }
Finally you need to place the content into the placeholder like this:
phContent.Controls.Add((Control)_content);
That last line goes into the Page_Init event. For reference "phContent" is the name of the place holder where you want the content to appear, like this:
<asp:Panel ID="pnlLockable" runat="server" Visible="False">
<asp:Placeholder runat="server" ID="phContent" />
</asp:Panel>
On the front end the resulting implementation looks like this:
<uc:MyControl runat="server" ID="lockit1">
<Content>
//...your stuff goes here...
</Content>
<uc:MyControl>
Note that I presume that what is inbetween the Content Tags is a root control. This is because I nested another user control in there. I imagine if you put whatever content you want within a panel or placeholder it should be fine.
Also you can read "How to: Create Templated ASP.NET User Controls". Really helpful.

Categories

Resources