TL;DR: All controls within a usercontrol that's being used outside it's home project are null when that usercontrol's Page_Init/Page_Load methods are called.
The setup is like this:
Projects "UI.Frontend", "UI.ControlPanel", and "UI.Common" are "ASP.NET Web Application"s. UI.Common is never meant to be accessed directly- it just contains UserControls that are needed in both the frontend and the control panel.
So, an aspx file (SomeFrontendPage.aspx) in UI.Frontend contains the lines:
<%# Register tagprefix="BP" Namespace="UI.Common" Assembly="UI.Common" %>
and later:
<BP:MyControl runat="server" ID="ctlMyControl" />
while over in UI.Common, there's a control named MyControl (normal ascx, ascx.cs, and ascx.designer.cs files). Now, when I open SomeFrontendPage.aspx in a browser, ctlMyControl gets loaded and it's init+load methods get executed. The problem is all subcontrols of MyControl never get initialized. Example (if MyControl.ascx has a textfield of ID txtBlah):
protected void Page_Init(object sender, EventArgs e)
{
txtBlah.Text = "test";
}
The above code will run, but will cause a null pointer (well, "Object reference not set to an instance of an object") since txtBlah will be null.
Edit:
An example control would be:
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="MyControl.ascx.cs" Inherits="Common.MyControl" %>
Whatever: <asp:TextBox ID="txtWhatever" runat="server" />
You may find you have more problems that what is immediately shown. ASCX files aren't embedded in assemblies by default, and when they are, you then need to create a virtual path provider to access them.
Can we see an example control?
Related
The Code:
ParentControl.ascx
<%# Control Language="C#" AutoEventWireup="true" CodeFile="ParentControl.ascx.cs"
Inherits="ParentControl" %>
<%# Register Src="~/ChildControl.ascx" TagPrefix="Prefix" TagName="ChildControlTag" %>
ParentControl.ascx.cs
public partial class ParentControl : UserControl
{
List<ASP.childcontrol_asxc> controlList = new List<ASP.childcontrol_asxc>();
... inside a public property setter ...
var control = new ASP.childcontrol_ascx(); // <ABC> what the heck is this reference?
controlList.Add(control);
...
}
ChildControl.ascx
<%# Control Language="C#" AutoEventWireup="true" CodeFile="ChildControl.ascx.cs"
Inherits="ChildControl" %>
<asp:Repeater ID="childRepeater" runat="server" EnableViewState="false"
ViewStateMode="Disabled">
ChildControl.ascx.cs
public partial class ChildControl : UserControl
{
...
protected void Page_Load(object sender, EventArgs e)
{
childRepeater.DataSource = xyz; // <XYZ> crashes if I don't use the weird reference
}
}
The Problem:
I don't understand what the reference comment marked with <ABC> is all about. That's not the class I defined... but Intellisense doesn't complain. If I press F12 on it, it takes me to the <%# Control ... %> tag at the top of ChildControl.ascx instead of the control definition in ChildControl.ascx.cs.
I don't understand what this other version of the control is, why it's in the ASP namespace, or what the implications of using it instead of the control directly are. Worse, this compiles fine on my local workstation, but throws a compiler error on the TFS server we use for CI.
The Question:
Does anyone know the name for this method of using/referencing the custom User Controls, and/or have links/information I can look at to get a better handle on what this is and what the implications are? I've been unable to find anything useful via Google. While a fix/workaround would be great to have - I would still like to be able to research the technique.
Explorations:
I've tried replacing the usages with the actual class name, instead of the weird ASP.class_ascx references... it compiles fine if I do this, but unfortunately it fails at runtime. It seems like the other reference changes how it interacts with the asp.NET lifecycle - server controls defined in the aspx of the child control are null in the Page_Load() of the child control (marked <XYZ>). Under the weird ASP.control_ascx reference approach, the repeaters are properly defined when it hits the Page_Load() of the child controls, but I don't understand why.
Miscellaneous:
The project is using the Roslyn compiler on my local workstation, via the DotNetCompilerPlatform NuGet package but I believe its just using the VS/TFS 2015 built in compiler on the CI server. This might explain why TFS throws compiler errors - it tells me The type or namespace name 'usercontrol_ascx' does not exist in the namespace 'ASP' (are you missing an assembly reference?). I'm looking at configuring TFS to use the compiler from the NuGet package which will then hopefully compile - but this is still weird and I'd like to understand it.
This is the class that the ASPX file compiles to. It inherits your class and adds code that renders your ASPX content.
I have a MasterPage (MyBoxx.Master) referencing 2 usercontrols :
<%# Master Language="C#" AutoEventWireup="true" CodeFile="MyBoxx.master.cs" Inherits="MyBoxxMaster" %>
<%# Register TagPrefix="uc1" TagName="Header" Src="Header.ascx" %>
<%# Register TagPrefix="uc1" TagName="Footer" Src="Footer.ascx" %>
My user control "Header" contains among other things a searchbox. I want to hide this searchbox when visiting some pages. Therefore I added a boolean property to my user control and use this property when rendering the usercontrol to determinate whether to display the search box or not :
public partial class uxHeader : System.Web.UI.UserControl
{
bool _showSearch = true;
public bool ShowSearch
{
get { return _showSearch; }
set { _showSearch = value; }
}
[...]
protected void Page_Load(object sender, EventArgs e)
{
[...]
searchBox.Visible = _showSearch;
}
}
I then try to access this "ShowSearch" Property from the content page :
((uxHeader)Page.Master.FindControl("Header1")).ShowSearch = false;
Problem is I get the following error when trying to compile :
Error 15 The type or namespace name 'uxHeader' could not be found (are you missing a using directive or an assembly reference?)
The thing is I'm sure I got it to work and compile at some point as it works on the previously released production version. But now I'm doing a change to something else in the same site, and can't compile anymore.
From various post on SO, I tried adding the following lines to my content page aspx :
<%# MasterType VirtualPath="~/MyBoxx.master"%>
<%# Reference VirtualPath="~/MyBoxx.master" %>
Without any success ! I saw also some answers about the page Lifecycle, but this can't be the problem here as I'm getting an error on compilation, not a bug upon execution.
If anyone has any advice on how I can fix this for good, I would grandly appreciate.
Thanks !
Well, I found several working solutions... and I think I understood how/why it worked earlier
1) it seems that compilation has a role to play in this. If I comment the line, compile the site, and then try to add the line again, the type uxHeader is "available" in VS and I can compile the site back again with the line uncommented...
2) As first solution is obviously not a long-term solution, I found that referencing the user-control (without actually using it of course) in the content page aspx would do the trick :
<%# Register TagPrefix="uc1" TagName="Header" Src="Header.ascx" %>
3) I also tried this one, which I find the cleanest...
In the master page, expose a public property :
public uxHeader PageHeader
{
get
{
return Header1;//Header1 is the id of the userControl dropped in masterpage
}
}
In the content page aspx, I then put :
<%# MasterType VirtualPath="~/DBoxx.master"%>
then, still in the content page, but in the codebehind, and after a compilation of the site, I can use :
this.Master.PageHeader.ShowSearch = false;
Hope this will help the ones searching for help on the subject in the future. I see this is a recurent question
Depending on how you have your User Control coded you may or may not be able to access all it's properties/methods when exposing it to the master page as a master page property..
Here is a solution that works:
In your master page you need to register your user control (.ascx) and place it on the master within the form tag.
Register the User Control
<%# Register Src="~/Controls/MyUserControl.ascx" TagPrefix="uc" TagName="MyUserControl" %>
Add the User Control to the Master Page
<form id="frmMain" runat="server">
<uc:MyUserControl runat="server" ID="ucMyUserControl" />
<div id="main-wrapper">
<div id="main">...
Now for the content page, you must create a reference in each of the content pages that use the master page for which you want to use the control.
Add the Reference in the content Page
<%# Reference Control="~/Controls/MyUserControl.ascx" %>
Now you can setup a public variable at the page level and access it's properties/methods
Partial Class MyPage
Inherits System.Web.UI.Page
Public usrCtrl As MyUserControl
Protected Sub Page_Load(sender As Object, e As EventArgs) Handles Me.Load
If Master.FindControl("ucMyUserControl") IsNot Nothing Then
usrCtrl = CType(Master.FindControl("ucMyUserControl"), MyUserControl)
usrCtrl.ExecMyMethod()
End If
...
During my development, I have a web user control project and another web project which will use the user controls from the web user control project.
So I copy the DocControl.ascx file to my web project and try to use the properties of the DocControl.ascx.
But VS does not know the properties of the control. So when I check the designer.cs, the reference is like that
protected global::System.Web.UI.UserControl Control;
Which should be
protected global::MSN.DocControl Control;
So I changed the name of the control from System.Web.UI.UserControl to MSN.DocControl and I can use the properties of the DocControl.ascx.
But my issue is whenever I modify ( eg. put a lable in aspx) the aspx file, the reference in designer.cs become
protected global::System.Web.UI.UserControl Control;
So I has to change it whenever I modify my aspx.
What should I do so I don't need to change the designer.cs
Thanks in advance......
I have solved it by moving
protected global::MSN.DocControl Control;
from designer.cs to .cs page.
So whenever you made any changes, it will be OK.
#kokbira - > hope that it helps you.
In my case, it was a bad src path in my register line. This caused no error messages, but would generate the generic control instead of the specific class, with the same symptoms you describe.
I had this (which has the wrong Src path):
<%# Register TagPrefix="uc" TagName="Pipes" Src="/Controls/Pipes.ascx" %>
...
<uc:Pipes id="ucPipes" runat="server" />
and it generated this, which is generic, and has none of the control's properties:
protected global::System.Web.UI.UserControl ucPipes;
When I did the correct path, with Category folder, it worked:
<%# Register TagPrefix="uc" TagName="Pipes" Src="/Category/Controls/Pipes.ascx" %>
...
<uc:Pipes id="ucPipes" runat="server" />
and generated this correct one, so all properties worked:
protected global::Company.Category.Controls.Pipes ucPipes;
I have a UserControl which uses a UserControl, among other controls.
In the ascx file I have the following code:
<%# Register TagPrefix="tag" Namespace="some.name.space" Assembly="some.assembly" %>
<tag:control ID="test" runat="server" />
In my Page_Load method, I try to set a property on test like so:
test.Text = "Hello World!";
This actually sets the Text property of a literal control in my user control test.
This throws an exception:
Object reference not set to an instance of an object
When it tries to set the
lblTest.Text = value;
The object that is null is lblTest.
Am I not adding the user control correctly? Should I - or do I have to - specify the Src property when registering a Tag? If so, I'd have to register every usercontrol I use?
This also results in no controls loading in usercontrol and all controls are null within usercontrol.
If the user control is in your current project, then you need to include the src in the register statement:
<%# Register TagPrefix="uc1" TagName="NavTop" Src="controls/NavTop.ascx" %>
However, if you use this user control in more than one page, then you can also register it in web.config:
<system.web>
<pages>
<controls>
<add tagPrefix="uc1" tagName="NavTop" src="~/controls/NavTop.ascx" />
</controls>
</pages>
</system.web>
One other thing to be aware of: there are times when the visual studio designer does not "see" your changes to controls on the page if you only make the changes in source view. If you change a control name, for example, you could end up with a control with the new name in the ascx but a reference to a control with the old name in the designer file. At runtime, this will result in the designer file property being null.
After having been burnt by this a number of times, if I make any changes in source view, I either check to see that the designer file has been updated correctly or I switch to design view, make a minor change, then save the page/user control.
I had this problem when I was adding a user control in the code behind the wrong way. You have to use the Page.LoadControl method to initialize the control you can't just use new.
//WRONG
UserControls.BingoCardPage bcp = new UserControls.BingoCardPage();
form1.Controls.Add(bcp);
//RIGHT
UserControls.BingoCardPage bcp = (UserControls.BingoCardPage)Page.LoadControl("~/UserControls/BingoCardPage.ascx");
form1.Controls.Add(bcp);
The issue here is usually due the the load mechanics of user controls, they load after the page typically. So as a result the controls have not yet been initialized on your usercontrol (causing the null ref) during the containing page_load method. One way to work around this is to just create and set a property on the usercontrol and have the usercontrol wire-up/populate its own UI in its Page_Load method.
Something like this:
//Page
protected void Page_Load(object sender, EventArgs e)
{
test.Text = "Hello World!";
}
//User Control
public string Text {get; set;}
protected void Page_Load(object sender, EventArgs e)
{
lblTest.Text = Text;
}
Please try to put code in Page_prerender event of page. It will work for you.
I have an ASP.NET (C#) page with some 3rd party controls, some ajaxy stuff and some normal ASP.NET Button controls.
The Button click events do not fire when clicked.
Double-clicking the button in design mode in VS 2008 switches to the code-behind but doesn't create the event handler.
Creating the event handler manually doesn't help.
The whole page is too big to include here, but this is the top bit:
<%# Page Language="C#" MasterPageFile="~/basewidepage2.master" AutoEventWireup="true" EnableEventValidation="false" CodeFile="CompanyCompliance.aspx.cs" Inherits="CompanyCompliancePage" Title="3DSS" %>
<%# Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="cc1" %>
<%# Register Assembly="obout_Grid_NET" Namespace="Obout.Grid" TagPrefix="cc2" %>
<%# Register Src="usercontrols/CalendarEx.ascx" TagName="CalendarEx" TagPrefix="uc2" %>
<%# MasterType VirtualPath="~/basewidepage2.master" %>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceholder1" runat="Server">
<script type="text/javascript">
// a bunch of function declarations
</script>
...and my button declaration on the page:
<asp:Button ID="LicenseCsvButton" runat="server" Text="Export to CSV" OnClick="LicenseCsvButton_Click" />
...and the code-behind:
protected void LicenseCsvButton_Click(object sender, EventArgs e)
{
// get data
CompanyCompliance cc = new CompanyCompliance(Master.theCompany.ID);
DataTable dt = cc.BusinessLicenses.Tables[0];
// send to browser as download
Tools.SendTableAsCsvToBrowser(Response, dt, "LicenseData");
}
Any ideas? could it be the ajax or something? Maybe the 3rd party "obout" grid control?
Update:
I did fix this a month or two ago, so I came back to this question to answer it for posterity but couldn't remember exactly how I fixed it! (Curse you, old age!) I had some limited success by replacing some of the ASP.NET AJAX controls with jQuery UI ones but I think the real solution was that one of the properties in the one of the tags was pointing to a control that no longer existed.
If you're in this same situation, try that and let me know what works in the comments and I'll post the correct answer.
During debugging, check the CausesValidation property of your button. For some reason, one of my pages had a button defaulting to "True." When I explicitly set it to "False" everything worked.
I know that this should be resolved by now, but just to share - I just had a similar issue. In my case, the problem was that I had a RequiredFieldValidator in a page, that wasn't visible because it was part of a popup. That validator was supposed to be invoked only when clicking its related "Save" button, but since I didn't have any ValidationGroup set, it would prevent the page to submit for any clicked button. Adding a ValidationGroup to the right button resolved the issue.
Experienced the same issue recently - cause was eventually determined to be that the button was disabled by a juavascript method onbeforesubmit (designed to prevent multiple submissions), and unfortunately web forms appears to check the enabled state of the button before it allows the codebehind event to trigger.
I had this problem just now and it was caused by another control having an AutoPostBack="true" which would submit the form before the button had a chance to submit the form to trigger the click event.
Change
CodeFile="CompanyCompliance.aspx.cs"
to
CodeBehind="CompanyCompliance.aspx.cs"
Related question: CodeFile vs CodeBehind
The inherits directive seems to point to a non-existant type.
Take a look in the code behind file of the CompanyCompliance page - ("CompanyCompliance.aspx.cs").
you should find the correct namespace and something like "public partial class xxx" where xxx is the name of the class which should correspond with your inherits directive. maybe you have to fully qualify the name as TJB already stated.
I had a similar issue, and it was really tricky. I recently migrated a VS 2005 ASP.NET 2.0 web forms app to VS 2010 ASP.NET 4.0.
It was difficult to setup and buggy as expected, but the issue of buttons not firing the click event was getting on my nerves.
In the end, it was as simple as not declaring a submit action in the site.master form. I changed:
<FORM runat="server" name="MainForm" method="post" action="Default.aspx" id="m_mainForm" enctype="multipart/form-data">
to
<FORM runat="server" name="MainForm" method="post" id="m_mainForm" enctype="multipart/form-data">
Boom. Problem solved. I hope it saves days of troubleshooting to someone. Sadly, I couldn't find anything about it on the internet by myself.
I had this problem I have changed the Button property "UseSubmitBehavior"=false. Now it is working.
For future answer seekers : If you are assigning the click handler in code behind, make sure that it is not inside an IsPostBack == false check :
void Page_Load (object oSender, EventArgs oEventArgs)
{
if (IsPostBack == false)
{
oButton += new EventHandler(oButton_Click); // does not work
}
oButton += new EventHandler(oButton_Click); // does work
}