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.
Related
I am working with the web application which I have only binaries. The application allows developing extension by providing internals to the derived classes.
What I would like to achieve is to add additional functionality to the existing aspx page. Because I can’t replicate and modify corresponding code I thought about developing a UserControl and modify markup of the discussed aspx page to include that control.
Until now I was successful. The control appears on the page and triggers server event handlers. It also has access to the application internal data. What I need now is to programmatically manipulate some of the original page elements from that UserControl server side.
I know that this is not the purpose of User Controls and they should not to have any knowledge about parrent page elements. However, this is as far as I know the only way to include some of the custom functionality to the existing page.
Before I asked this question I have spent a good amount of time for researching avaiable solutions.
Please, could you suggest the best possible way of referencing those elemnent from the User Control at server side?
Below is a simplified code representation of what I have done so far
The existing aspx page:
// SOME CONTENT OF THE ORGINAL PAGE
<%# Register TagPrefix="uc" TagName="MyControl" Src="~/usercontrols/MyControl.ascx" %>
// SOME CONTENT OF THE ORGINAL PAGE
<uc:MyControl ID="pnlMyControl" runat="server"></uc:MyControl>
// SOME CONTENT OF THE ORGINAL PAGE
My User Control:
public partial class MyControl : System.Web.UI.UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
//DO SOMETHING HAVING ACCESS TO INTERNAL DATA
}
protected void lnkTest_Click(object sender, EventArgs e)
{
//DO SOMETHING HAVING ACCESS TO INTERNAL DATA
}
}
I've done something similar, though I've done it for variables rather than controls so I shall attempt to adapt it here.
I used properties to achieve this, working with:
<%# Register TagPrefix="uc" TagName="MyControl" Src="~/usercontrols/MyControl.ascx" %>
<uc:MyControl ID="pnlMyControl" runat="server" />
In the UserControl you do something like:
private string _myTextBox = new TextBox();
public string myTextBox
{
get
{
return _myTextBox;
}
set
{
_myTextBox = value;
}
}
Then in the parent page, you can set these properties; for example:
protected void Page_Load(object sender, EventArgs e)
{
pnlMyControl.myTextBox = MyParentTextBox;
}
Also, you may find this useful; you can directly fire methods on the parent from the user control using this:
this.Page.GetType().InvokeMember("MyMethodName", System.Reflection.BindingFlags.InvokeMethod, null, this.Page, new object[] { });
I hope that helps.
I have an .aspx page in which I have a property. Now i create a user control and drop it on the page. Now how can i access that property in code behind of usercontrol.
The best way is to expose a public property in the UserControl and assign that property from the ASPX page:
By code:
var uc = this.myUserControl as MyCuserControlType;
uc.CustomUserControlProperty = this.MyPageProperty;
Declaratively
<uc:MyUserControlType1 runat="server= ID="myUserControl" CustomUserControlProperty="<%# this.MyPageProperty %>" />
Note: If you want to use declarative markup you would need to call this.DataBind(); in code to force the binding
Edit 1
In case you want to do the opposite (pass a value from the control to the page in response to an event) you could declare your own custom event in the user control and fire it when needed it.
Example:
User control code behind*
public event Action<string> MyCustomEvent = delegate{};
....
// somewhere in your code
this.MyCustomEvent("some vlaue to pass to the page");
Page markup
<uc:MyUserControl1 runat="server" onMyCustomEvent="handleCustomEvent" />
Page code behind
public void handleCustomEvent(string value)
{
// here on the page handle the value passed from the user control
this.myLabel.Text = value;
// which prints: "some vlaue to pass to the page"
}
If a user control needs to access something on the parent page, then maybe this user control should have included it as its own property which could be set from the parent. Ideally user controls should be independent from any parent context or other user controls on the page, otherwise they really are not something reusable. They need to be self contained and configurable throughout their the properties they are exposing.
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;
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?
We are trying here to localize our user control basically we want to be able to do something like this :
<in:Banner runat="server" ID="banners" Lang="fr" />
The way we do this is by page level and send it to master that then send it to the control:
protected void Page_Load(object sender, EventArgs e)
{
Master.Lang = "FR";
}
Then in the MasterPage.master we do something like this :
<in:Banner runat="server" ID="banners" Lang="<%= Lang %>" />
The masterpage has a public proprety named Lang.
In the control we have set a field that contains the default language and a proprety (Lang) that set the language. It seems that whatever we do, the current language is not sent from the page to the usercontrol... any help?
Not exactly like that, but you can consider the content page like a control in the master page, so its likely that the page load of the page is executing before the page load of that user control.
Regardless of the above, why not set the ui culture to the asp.net thread (probably from the global.asax), and using that from the control.
Another alternative is to have a separate class where you hold the current language, and expose a change event ... that way you can make sure to use the right language even if the load is done differently --- or there is a change language event later.
You can access it in code-behind of the MasterPage like this
public void SetLanguage(string language)
{
banners.Lang = language; //banners is an ID reference to your user control.
}
Or in your markup I think you can do it like this
<in:Banner runat="server" ID="banners" Lang='<%# Bind("Lang") %>' />
I should mention that Bind works in .Net 2.0 and up.