User Control and constructor - c#

i have built a user control with web controls in ascx page.
//ascx file
<%# Control Language="C#" AutoEventWireup="true" ClassName="Product"CodeFile="Product.ascx.cs" Inherits="Usercontrols_Product" %>
<link href="../StyleSheet/StyleSheet.css" rel="stylesheet" type="text/css" />
<div>
<asp:Panel ID="box" CssClass="productBox" runat="server">
<asp:Image ID="imgProduct" CssClass="productImage" runat="server" /><br />
<asp:Label ID="lblProductName" CssClass="productLbl" runat="server"></asp:Label><br/>
<asp:Label ID="lblProductPrice" CssClass="productLbl" runat="server"></asp:Label>
</asp:Panel>
</div>
in the cs file of user control i created acontructor which get another class reference.
whith the class i get in contructor i want insert data to child controls.
//ascx.cs file
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class Usercontrols_Product : System.Web.UI.UserControl
{
public EventHandler cmdDetailsClick;
protected Product thisProduct;
public Usercontrols_Product( Product pr)
{
thisProduct = pr;
imgProduct.ImageUrl = thisProduct.ImageUrl;
lblProductName.Text = thisProduct.CompanyName + "<br/>" + thisProduct.ProductName + "&nbsp" + thisProduct.Model;
lblProductPrice.Text = thisProduct.Price.ToString() + "&nbsp" + "israeli shekel";
}
public Usercontrols_Product()
{
}
protected void cmdContinue_clicked(object sender, EventArgs e)
{
//we send to event product class of sender
if (cmdDetailsClick != null)
cmdDetailsClick(thisProduct, EventArgs.Empty);
}
}
the problem is that now with spesial constructor web controls from aspx file are not being
initiallized. i tried initiallize them in code with new keyword but than they are with no attributes from ascx file. with no special constructor its works fine .but i need this special constructor. how can i initiallize this webcontrols whith their attributes from ascx file

The UserControl is instantiated by Page (i.e. constructor of user control is out of your control) - you can define one, but the default constructor will be called instead. If you want to pass data, there are numerous techniques how to do so; simplest way:
public Product Product {
set {
thisProduct = value;
imgProduct.ImageUrl = value.ImageUrl;
lblProductName.Text = value.CompanyName + "<br/>" +
value.ProductName + "&nbsp" + value.Model;
lblProductPrice.Text = value.Price.ToString() + "&nbsp" + "israeli shekel";
}
}
To clarify how the process work on behind:
.aspx (or .ascx) file are being compiled on runtime by IIS.
So for example if you have simple user control:
<%# Control CodeBehind="FooControl.ascx.cs" Inherits="TestApplication.FooControl" %>
<asp:Literal ID="litBar" runat="server" Text="Whatever" />
IIS will make something like this from your control (shortened):
namespace ASP {
public class foocontrol_ascx : global::TestApplication.FooControl {
private static bool #__initialized;
public foocontrol_ascx() {
((global::WebApplication4.FooControl)(this)).AppRelativeVirtualPath = "~/FooControl.ascx";
if ((global::ASP.foocontrol_ascx.#__initialized == false)) {
global::ASP.foocontrol_ascx.#__initialized = true;
}
}
private global::System.Web.UI.WebControls.Literal #__BuildControllitBar() {
global::System.Web.UI.WebControls.Literal #__ctrl;
#__ctrl = new global::System.Web.UI.WebControls.Literal();
this.litBar = #__ctrl;
#__ctrl.ID = "litBar";
#__ctrl.Text = "Whatever";
return #__ctrl;
}
private void #__BuildControlTree(foocontrol_ascx #__ctrl) {
global::System.Web.UI.WebControls.Literal #__ctrl1;
#__ctrl1 = this.#__BuildControllitBar();
System.Web.UI.IParserAccessor #__parser = ((System.Web.UI.IParserAccessor)(#__ctrl));
#__parser.AddParsedSubObject(#__ctrl1);
}
protected override void FrameworkInitialize() {
base.FrameworkInitialize();
this.#__BuildControlTree(this);
}
}
}
Notice the built class inherits from your code behind and takes care about the markup as well (see how it creates literal litBar and set text to "Whatever"). Also this class has only one constructor - default constructor (so it naturally calls default constructor from class in code behind). I.E. - you can define custom constructor for your control but you have to provide default constructor anyway (so the built can work with it) and the built class ignores it (as the IIS can have no clue what parameters you want to pass to your custom constructor).

Related

Calling Dynamically Created Textboxes in C# Visual Studio

In this post I wanted to figure out how to create dynamically created textboxes in C# Visual Studio.
Adding additional textboxes to aspx based on xml
However, when I try to call the ID of these dynamically created textboxes later in my code to figure out what text the user entered into them, I am getting an error that says these IDs do not exist in the current context. Does anyone know how I would be able to call these?
credit to Adding additional textboxes to aspx based on xml
Here is my entire code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Xml.Linq;
namespace WebApplication4
{
public partial class WebForm15 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsCallback)
{
//credit to https://stackoverflow.com/questions/44076955/adding-additional-textboxes-to-aspx-based-on-xml#comment75336978_44078684
const string xml = #"<Number>
<Num>1</Num>
<Num>2</Num>
<Num>3</Num>
</Number>";
XDocument doc = XDocument.Parse(xml);
int i = 0;
foreach (XElement num in doc.Root.Elements())
{
TextBox box = new TextBox
{
ID = "dynamicTextBox" + i,
Text = num.Value,
ReadOnly = false
};
divToAddTo.Controls.Add(box);
divToAddTo.Controls.Add(new LiteralControl("<br/>"));
i++;
}
}
}
protected void BtnGetValues_Click(object sender, EventArgs e)
{
IList<string> valueReturnArray = new List<string>();
foreach (Control d in divToAddTo.Controls)
{
if (d is TextBox)
{
valueReturnArray.Add(((TextBox)d).Text);
}
}
//valueReturnArray will now contain the values of all the textboxes
}
}
}
Here is aspx:
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm15.aspx.cs" Inherits="WebApplication4.WebForm15" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
</head>
<body>
<form id="form1" runat="server">
<div id="divToAddTo" runat="server" />
<asp:Button runat="server" ID="BtnGetValues" Text="GetValues" OnClick="BtnGetValues_Click" />
</form>
</body>
</html>
Figured it out!!! Here is what I found after scouring the internet for hours
Solution:
When using dynamic controls, you must remember that they will exist only until the next postback.ASP.NET will not re-create a dynamically added control. If you need to re-create a control multiple times, you should perform the control creation in the PageLoad event handler ( As currently you are just creating only for first time the TextBox using Condition: !IsPostabck ). This has the additional benefit of allowing you to use view state with your dynamic control. Even though view state is normally restored before the Page.Load event, if you create a control in the handler for the PageLoad event, ASP.NET will apply any view state information that it has after the PageLoad event handler ends.
So, Remove the Condition: !IsPostback, So that each time the page Loads, The TextBox control is also created. You will also see the State of Text box saved after PageLoad handler completes. [ Obviously you have not disabled ViewState!!! ]
Example:
protected void Page_Load(object sender, EventArgs e)
{
TextBox txtBox = new TextBox();
// Assign some text and an ID so you can retrieve it later.
txtBox.ID = "newButton";
PlaceHolder1.Controls.Add(txtBox);
}
Now after running it, type anything in text box and see what happens when you click any button that causes postback. The Text Box still has maintained its State!!!

NullReferenceException when assigning a Session variable/value

I have in many places in my ASP.NET project used the Session variable for storing data. I usually write something like this:
public uint MyPropery
{
get
{
object o = Session["MyProperty"];
if (o != null)
return (uint)o;
else
return 0;
}
set
{
Session["MyProperty"] = value;
}
}
However, this time I get a NullReferenceException in the setter. As far as I know, it is valid to assign the Session variable in the manner above. Also, Session is not null and neither is value.
Any ideas on this?
Edit:
Adding the code for the UserControl in which the property exists. I am using ext.net but that shouldn't have anything to do with this. One thought that crossed my mind:
The UserControl (seen below) is added dynamically in code-behind of a page. Can that have anything to do with it?
I am adding UserControls like this (on a Page):
foreach(CoreCommons.System.Comment c in cg.Reply_Comments)
{
WebApplicationExtNetTest.Secure.UserControls.CoreComment cc = new UserControls.CoreComment();
cc._Comment = c; // here is where i get the NullRef
this.Panel1.ContentControls.Add(cc);
}
Markup:
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="CoreComment.ascx.cs" Inherits="WebApplicationExtNetTest.Secure.UserControls.CoreComment" %>
<%# Register Assembly="Ext.Net" Namespace="Ext.Net" TagPrefix="ext" %>
<ext:Panel runat="server" ID="CoreCommentOuterPanel" BodyStyle="background: #FFFDDE">
<Items>
<ext:ColumnLayout runat="server">
<Columns>
<ext:LayoutColumn ColumnWidth="0.8">
<ext:Image runat="server" ImageUrl="/Resources/bullet_triangle_green_16x16.png" Align="AbsMiddle"></ext:Image>
<ext:Label runat="server" ID="lblCommentInfo"></ext:Label>
</ext:LayoutColumn>
<ext:LayoutColumn ColumnWidth="0.2"><ext:Button runat="server" ID="btnDelete" Icon="Delete"></ext:Button></ext:LayoutColumn>
</Columns>
</ext:ColumnLayout>
<ext:Label runat="server" ID="lblComment"></ext:Label>
</Items>
</ext:Panel>
Code-behind:
namespace WebApplicationExtNetTest.Secure.UserControls
{
public partial class CoreComment : System.Web.UI.UserControl
{
public CoreCommons.System.Comment _Comment
{
get
{
object o = Session["CoreComment_ObjectId"];
if (o != null)
return (tWorks.Core.CoreCommons.System.Comment)o;
else
return null;
}
set
{
Session["CoreComment_ObjectId"] = value;
SetComment();
}
}
protected void Page_Load(object sender, EventArgs e)
{
}
private void SetComment()
{
if (_Comment == null)
{
lblCommentInfo.Text = "";
lblComment.Text = "";
}
else
{
lblCommentInfo.Text = _Comment.Author + ", " + _Comment.TimeStamp.ToString("g");
lblComment.Text = _Comment.Text;
}
}
}
}
I'm almost completely sure the NullReferenceException is thrown in SetComment() because none of the CoreComment's child controls (lblComment, lblCommentInfo) are properly instantiated at the point you set the _Comment property.
The reason these child controls are not instantiated is indeed the way you currently add the CoreComment controls. For dynamically adding UserControls, you must use Page.LoadControl() (see: here) to create a new instance of the control, as it does some behind-the-scenes magic to ensure it is properly initialized, which includes the instantiation of the child controls.
On a sidenote, personally I'd change SetComment() to SetComment(CoreCommons.System.Comment comment) and use the parameter instead of repeatedly calling the getter, or, if staying with the original, at least call the getter only once and store the result in a local variable. With what I assume is probably InProc session storage it won't make much of a difference, but in any other storage mode you'd repeatedly deserialize the Comment object for no reason.
You need to use the Page.LoadControl() method instead , please look here
BTW:the problem is in adding the control programatically with that way.
Use:
return Session["MyProperty"] as uint? ?? 0;
and post somewhere full exception stack trace with inner exception(s)

Can't set tag/attribute value using c# codebehind on aspx page

I have a custom .ascx control and would like to set one of it's properties using code. In the .aspx I have this:
<uc1:CustomContent ID="bunchOfContent" runat="server" contentPayload='<%# getRegionID() %>' />
In the codebehind I have:
public partial class Region : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
... things
}
public string getRegionID()
{
//return "region_" + Request["region"];
return "thevalueIwant";
}
However, the value I want is not populated and the code is not invoked (breakpoints are not triggered).
What am I doing wrong? I've tried various changes like changing the quotes from " to ' to no quotes at all. Also I've used <%= instead of <%# but no luck. Thanks!
In the Page_Load method, you can do:
bunchOfContent.contentPayload = getRegionID();
The reason why <%# ... %> did not work is because that's the form you use for databinding. In order for the code you put in there to be executed, you need to call the DataBind() method somewhere. And as for <%= ... %>, that's not suitable for setting a server control property, it simply is a short form of <% Response.Write(...) %>.

ASP.NET C# scope issue

OK, so I'm tyring to work with some simple stuff in ASP.NET and C# to get the hang of the super super basics, and I'm having trouble finding out how I can get this scope issue to work. At least, I think it's a scope issue! :)
So, here is my Default.aspx presentation markup:
<%# Page Language="C#" Inherits="project1.Tree" %>
<!DOCTYPE html>
<html>
<head runat="server">
<title>project1_test</title>
</head>
<body>
<form runat="server">
<p><asp:label runat="server" id="lblOutput" /></p>
<asp:TextBox ID="txtGrowBy" runat="server" />
<asp:Button id="btnGrow" runat="server" Text="Grow!!!" />
</form>
</body>
</html>
And here is my CodeBehind file:
using System;
using System.Web;
using System.Web.UI;
namespace project1
{
public partial class Tree : System.Web.UI.Page
{
public int height = 0;
public void Grow(int heightToGrow) {
height += heightToGrow;
}
protected void Page_Load(Object Source, EventArgs E)
{
Tree tree1 = new Tree();
string msg = "Let's plant a tree!<br/>";
msg += "I've created a tree with a height of " +
tree1.height + " metres.<br/>";
lblOutput.Text = msg;
}
public virtual void btnGrowClicked (object sender, EventArgs args)
{
txtGrowBy.Text = tree1.heightToGrow;
}
}
}
Now, I believe the issue lies with the fact that I'm not using a getter and sender, but I'm not 100% sure.
I take it you're variable height is not being maintained between postbacks?
This is because the web is stateless. Your variables are not maintained between postbacks unless you store the values in Session, ViewState or Hidden Fields. So you could do the following to maintain your height value between PostBacks:
ASPX:
<form runat="server">
<asp:HiddenField id="hd_Height" runat="server" />
</form>
Code Behind:
public int Height
{
get
{
return int.Parse(hd_Height.Value).ToString();
}
set
{
hd_Height.Value = value.ToString();
}
}
There's several immediate problems with your code; in the Page_Load method, you're creating a new Tree instance - you don't have to do this, as one was automatically created by IIS when the ASP.NET page was accessed. Use the this keyword in the Page_Load method to get access to that instance.
Further, nothing ever seems to call the Grow method; is this intentional? Shouldn't you be calling that from within the btnGrowClicked method?
And finally as GenericTypeTea points out, your height field won't be maintained between Postbacks. Easiest way to do this is with session state, eg:
private void PersistHeight(int height)
{
this.Session["height"] = height;
}
private int RestoreHeight()
{
return (int)this.Session["height"];
}
You could use viewstate as well (if Mono supports it); simply add the updated value to viewstate before giving control back to the browser. Then read from viewstate the original value saved in the last postback and incrementing the new value to it:
public int MyValue
{
get {return Convert.ToInt32(viewstate["myVal"]);}
set {viewstate["myVal"] = value;}
}
I hope that makes sense.

Adding an ASP.NET Web User Control to a Control Dynamically

I have a simple ASP.NET Web User Control. It looks like this:
<%# Control Language="C#" AutoEventWireup="true"
CodeBehind="NewsArticle.ascx.cs"
Inherits="Website.Controls.NewsArticle" %>
<div>
<asp:Literal ID="ltlBody" runat="server" />
</div>
My code behind looks like this:
namespace Website.Controls
{
public partial class NewsArticle : System.Web.UI.UserControl
{
public String bodyText
{
//get { return ltlBody.Text; }
set { ltlBody.Text = value; }
}
}
}
On a .aspx page I have <asp:Panel ID="pNews" runat="server" />
In the code behind I have:
foreach (vwNews news in newsQuery)
{
NewsArticle article = new NewsArticle();
article.bodyText = news.Body;
pNews.Controls.Add(article);
}
Every time I run this code the newsQuery is populated correctly and I get to the line
aticle.bodyText = news.Body; and then I received the error article.bodyText threw an exception of type 'System.NullReferenceException'
I am not sure what is causing this error message or how to fix it. I would think that there should not be an issue. I tried creating a constructor for my Web User Control so that it would give default values to my properties but that didn't work. Any idea how to make this work? It doesn't seem like it should be that
To load a control programatically you need to use the Page.LoadControl() method. See this MSDN article
You have a typo within the code you've written. 'aticle' instead of 'article'.

Categories