Don't know how to use custom controls in code behind - c#

I made a simple control with 1 text box.
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="sTextBox.ascx.cs" Inherits="TestingASPNET.Controls.sTextBox" className="sTextBox"%>
<asp:Textbox runat="server" ID="tbNothing"/>
<br />
I call this control as a reference in my default.aspx Here's the simple code.
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="default.aspx.cs" Inherits="TestingASPNET._default" %>
<%# Reference Control="~/Controls/sTextBox.ascx"%>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:PlaceHolder runat="server" id="PlaceHolder1" />
</div>
</form>
</body>
</html>
In my code behind in default.aspx.cs I have.
protected void Page_Load(object sender, EventArgs e)
{
PlaceHolder1.Controls.Add(LoadControl("~/Controls/sTextBox.ascx"));
PlaceHolder1.Controls.Add(LoadControl("~/Controls/sTextBox.ascx"));
}
This adds the 2 sTextBox onto my page.
The problem I'm having is how to I use the control like I would a normal textBox. For example.
TextBox tb = new TextBox();
tb.Text = "textbox";
PlaceHolder1.Controls.Add(tb);
This adds a text box on the page with the text "textbox" in it.
Can Someone give me a way to do EXACTLY this, but with the control sTextBox.

you can get that behavior by adding properties to your custom control.
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
var ctrl = (sTextBox) Page.LoadControl("~/sTextBox.ascx");
ctrl.Text = "something";
placeHolder1.Controls.Add(ctrl);
}
}
User Control :-
public partial class sTextBox : System.Web.UI.UserControl
{
public string Text { get; set; }
}

I couldn't get your code to work.
I either had to
var ctrl = (ProjectName.Controls.sTextBox) Page.LoadControl("~/Controls/sTextBox.ascx");
or import the control
using ProjectName.Controls;
When I did this, it worked.
Also your get set property wasn't work either, I had to change it to.
public string Text {
get
{
return tbNothing.Text;
}
set
{
tbNothing.Text = value;
}
}
Afterwards I added 1 more textbox into the control totaling 2. I changed the ID to tb1Text and tb2Text. I then had to get 2 methods for my get sets, which was
public string tb1Text {
get
{
return tb1.Text;
}
set
{
tb1.Text = value;
}
}
public string tb2Text
{
get
{
return tb2.Text;
}
set
{
tb2.Text = value;
}
}
inside my default code behind, I had to use
sTextBox ctrl = (sTextBox)Page.LoadControl("~/Controls/sTextBox.ascx");
ctrl.tb1Text = "something";
ctrl.tb2Text = "something 2";
PlaceHolder1.Controls.Add(ctrl);
This worked, now I know how to use 2 textboxes on 1 control :) . Hopefully it's the same with other controls that I have to make :S

Related

Get value from my own web control

I write one example to create own control on ASP.NET Froms. The controls very simple- combobox and button. User need choose value and when after he submit the button, the value from combobox need display in label.
So. Code of my Control:
public class MyControl:Control,IPostBackEventHandler
{
protected override void Render(HtmlTextWriter writer)
{
writer.AddAttribute("size","1");
writer.AddAttribute("ID","List2");
writer.AddAttribute("name", "ListYear");
writer.RenderBeginTag(HtmlTextWriterTag.Select);
for (int i = 1950; i < DateTime.Now.Year; i++)
{
writer.RenderBeginTag(HtmlTextWriterTag.Option);
writer.WriteEncodedText(i.ToString());
writer.RenderEndTag();
}
writer.RenderEndTag();
writer.AddAttribute("type","submit");
writer.AddAttribute("value","ClickMe");
writer.AddAttribute("name","BtnChange");
writer.RenderBeginTag(HtmlTextWriterTag.Input);
writer.RenderEndTag();
base.Render(writer);
}
public delegate void OnClickEventHandler(object sender, EventArgs args);
public event OnClickEventHandler Click;
public void RaisePostBackEvent(string eventArgument)
{
Click(this, new EventArgs());
}
}
The Page ASP:
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="TestMyControl.aspx.cs" Inherits="Hello.TestMyControl" %>
<%# Register assembly="Hello" namespace="Hello" tagPrefix="MyContrl" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Label ID="Label1" runat="server" Text="Label" Visible="False"></asp:Label>
<br />
<MyContrl:MyControl runat="server" OnClick="Unnamed1_OnClick" ID="Control1"></MyContrl:MyControl>
</div>
</form>
</body>
</html>
And in the end Event function:
protected void Unnamed1_OnClick(object sender, EventArgs args)
{
Label1.Visible = true;
Label1.Text="You choose "+Control1.????+" year";
}
What substitute for a question mark that take the value from the list?
P.S. Something strange is going on. Because when I click the button, the handler is not called, and I can not get into Unnamed1_OnClick
Since you have set the value on an attribute, to retrieve it you need to access Attributes property
Make your control inherit from HtmlControl
public class MyControl : HtmlControl, IPostBackEventHandler
{
...
On your page
<MyContrl:MyControl runat="server" OnClick="Unnamed1_OnClick" ID="Control1"></MyContrl:MyControl>
On your code
Label1.Text = Control1.Attributes["value"];
You can debug this line to see all available attributes
You would need to pass the name of the combobox and its the value of the text that is selected.
Like this:
protected void Unnamed1_OnClick(object sender, EventArgs args)
{
Label1.Visible = true;
Label1.Text="You choose "+ myCustomControl.SelectedItem.Value.ToString()
+ " year";
}
(Sorry. I misread the initial post and edited my code accordingly once I realized my mistake.)
Add select list to your user control with name="YourSelectList"
then in the click event handler
protected void Unnamed1_OnClick(object sender, EventArgs args)
{
Label1.Visible = true;
Label1.Text="You choose "+Control1.YourSelectList.SelectedValue.ToString()+" year";
}

How to disable user control from code-behind?

I have 2 user controls in an ASPX page. By default the second user control should be disabled. In that user control i am having only one text box. So i find the control in the page load event like this:
TextBox txtLocation = (TextBox)PI_CompLocationTree.FindControl("txtLocation");
txtLocation.Enabled = false;
But i am getting txtLocation as null. How do I get the control in the ASPX page from the ASCX control?
My Updated Code..In Aspx page..
<%# Register Src="~/UserControl/PI_CompLocationTree.ascx" TagName="PI_CompLocationTree"
TagPrefix="uc1" %>
<div id="Div2">
<div class="location">
<div class="usLocation">
<uc1:PI_CompLocationTree ID="PI_CompLocationTree1" runat="server"/>
</div>
</div>
</div>
In Page Load...
PI_CompLocationTree PI_CompLocationTree = new PI_CompLocationTree();
protected void Page_Init(object sender, EventArgs e)
{
var userControl = (PI_CompLocationTree)this.FindControl("PI_CompLocationTree1");
userControl.EnabledTextBox = false;
}
In ASCX Page...
<asp:TextBox ID="txtLocation" CssClass="fadded_text fadded_text_ctrl" Style="width: 260px;
float: left;" runat="server" Text=""></asp:TextBox>
In ASCX Code Behind...
public partial class PI_CompLocationTree : System.Web.UI.UserControl
{
public bool EnabledTextBox
{
get { return txtLoc.Enabled; }
set { txtLoc.Enabled = value; }
}
}
Use FindControl Methods as Follow..
1. UserControlClass objOfUserControl = (UserControlClass)Page.FindControl("UserControlID");
TextBox txtLocation= objOfUserControl.FindControl("txtLocation");
txtLocation.Enabled = false;
2.You Can Also use Public Property as Follow
In User Control Codebehind
public bool TextBoxUSC
{
set{txtLocation.Enabled = value;}
}
In Aspx Code Behind
UserControlClass.TextBoxUSC=false;
If You are using Master Page
ContentPlaceHolder cph = (ContentPlaceHolder)this.Page.Master.FindControl("MainContent");//"MainContent" is ContentPlaceHolder's ID
UserControlClass userCntrl = (UserControlClass)cph.FindControl("UserControlID");
userCntrl.TextBoxUSC = false;
Try this
Edited
Make Enabled false in aspx you can make like this:
Add property to your UC:
public bool EnabledTextBox
{
get{return IdTextBox.Enabled;}
set{IdTextBox.Enabled=value;}
}
then in aspx:
IdOfYourUserControlWithProperty.EnabledTextBox = false;
Hope it helps
Robin You can delete
TextBox txtLocation = (TextBox)PI_CompLocationTree.FindControl("txtLocation");
txtLocation.Enabled = false;
In your aspx, add forms with runat="server"
Delete also
PI_CompLocationTree PI_CompLocationTree = new PI_CompLocationTree();
You don't need because you use FindControl
Your work is good
PI_CompLocationTree1.EnabledTextBox = false; //from .aspx page. There's no need to use FindControl if you've added it statically to the webpage.

Access a textbox in C# that is created on fly

My code generates an TextBox on the fly in C# (page_load function). Can I access it in the code later? It does give me compilation error and does not seem to work. Can someone verify ?
Code for additonal problem
aContent += "<table>";
aContent += "<tr><td>lablel </td><td style='bla blah'><input type='textbox' id='col-1' name='col-1'/></td></tr> ... 10 such rows here
</table>"
spanMap.InnerHtml = aContent;
The contents are rendered OK but recusrive iteration does not return the textbox. I am calling it like this
TextBox txt = (TextBox)this.FindControlRecursive(spanMap, "col-1");
// txt = (TextBox) spanMapping.FindControl("col-1"); this does not work too
if (txt != null)
{
txt.Text = "A";
}
Assuming that you're persisting it correctly, you should be able to access it in code-behind using the FindControl method. Depending on where the control is, you may have to search recursively through the control hierarchy:
private Control FindControlRecursive(Control root, string id)
{
if (root.ID == id)
{
return root;
}
foreach (Control c in root.Controls)
{
Control t = FindControlRecursive(c, id);
if (t != null)
{
return t;
}
}
return null;
}
Using FindControlRecursive:
TextBox txt = this.FindControlRecursive(Page.Form, "TextBox1") as TextBox;
if (txt != null)
{
string text = txt.Text;
}
If you still can't find it using the above method, make sure that you're creating the control during after every postback, somwhere before Page_Load, like OnInit.
EDIT
I think you need to change the way you're adding content to the container. Instead of using a <span>, I would use a Panel, and instead of building markup, simply add controls to the panel in code-behind:
TextBox txt = new TextBox();
txt.ID = String.Format("txt_{0}", Panel1.Controls.Count);
Panel1.Controls.Add(txt);
Here's an example:
<%# Page Language="C#" %>
<script type="text/C#" runat="server">
protected void Page_Load(object sender, EventArgs e)
{
var textBox = new TextBox();
textBox.ID = "myTextBox";
textBox.Text = "hello";
Form1.Controls.Add(textBox);
}
protected void BtnTestClick(object sender, EventArgs e)
{
var textBox = (TextBox)Form1.FindControl("myTextBox");
lblTest.Text = textBox.Text;
}
</script>
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<form id="Form1" runat="server">
<asp:LinkButton ID="btnTest" runat="server" Text="Click me" OnClick="BtnTestClick" />
<asp:Label ID="lblTest" runat="server" />
</form>
</body>
</html>

Trigger for UpdatePanel disappearing when added to a "custom control"

Basically, in a nutshell, the problem is that dynamically generated triggers for an UpdatePanel can no longer be found (by ASP.NET) as soon as I add them as children of a custom control.
Since the amount of code I'm working on is quite substantial I've recreated the problem on a smaller scale, which will make it easier to debug.
The error thrown in my face is:
A control with ID 'theTrigger' could not be found for the trigger in UpdatePanel 'updatePanel'.
I'm not sure whether this implementation of a "custom control" is the right way to go about it, but I did not write the original implementation: I'm working with code written by a previous developer to which I cannot make large modifications. It looks a little unusual to me, but, alas, this is what I've been given.
Default.aspx
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="TestWeb.Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Panel runat="server" ID="panel">
</asp:Panel>
<asp:ScriptManager ID="scriptManager" runat="server"></asp:ScriptManager>
<asp:UpdatePanel runat="server" ID="updatePanel" UpdateMode="Conditional">
<ContentTemplate>
<asp:Label ID="lblSomething" runat="server"></asp:Label>
</ContentTemplate>
</asp:UpdatePanel>
</div>
</form>
</body>
</html>
Default.aspx.cs
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace TestWeb
{
public partial class Default : Page
{
protected void Page_Load(object sender, EventArgs e)
{
UselessTableWrapper table = new UselessTableWrapper();
TableRow tr = new TableRow();
TableCell td = new TableCell();
LinkButton button1 = new LinkButton { ID = "theTrigger", Text = "Click Me" };
button1.Click += button1_Click;
td.Controls.Add(button1);
tr.Controls.Add(td);
table.AddRow(tr);
panel.Controls.Add(table);
// ### uncomment these lines (and comment the one above) to see it working
// ### without the custom control
/*
Table realTable = new Table();
realTable.Controls.Add(tr);
panel.Controls.Add(realTable);
*/
updatePanel.Triggers.Add(new AsyncPostBackTrigger { ControlID = "theTrigger", EventName = "Click" });
scriptManager.RegisterAsyncPostBackControl(button1);
}
protected void button1_Click(object sender, EventArgs e)
{
lblSomething.Text = "Random number: " + new Random().Next(100);
updatePanel.Update();
}
}
}
MyControl.cs
using System;
using System.Web.UI.WebControls;
namespace TestWeb
{
public class UselessTableWrapper : WebControl
{
private Table table = new Table();
protected override void OnPreRender(EventArgs e)
{
Controls.Add(table);
}
public void AddRow(TableRow row)
{
table.Controls.Add(row);
}
}
}
Any ideas would be greatly appreciated.
Edit
I've tried switching the OnPreRender event for this (found in a tutorial):
protected override void RenderContents(HtmlTextWriter writer)
{
writer.BeginRender();
table.RenderControl(writer);
writer.EndRender();
base.RenderContents(writer);
}
... hoping that it would fix it, but it does not.
this is the approach that I've taken with loading a ascx web control inside an aspx control from the code behind.
In the control:
namespace dk_admin_site.Calculations
{
public partial class AssignedFieldCalculation : System.Web.UI.UserControl
{
public static AssignedFieldCalculation LoadControl(Calculation initialData)
{
var myControl = (AssignedFieldCalculation) ((Page) HttpContext.Current.Handler).LoadControl(#"~\\Calculations\AssignedFieldCalculation.ascx");
myControl._initialData = initialData;
return myControl;
}
private Calculation _initialData;
public Calculation Data { get { return _initialData; } }
protected void Page_Load(object sender, EventArgs e) {}
}
}
in the web form code behind:
protected void Page_Load(object sender, EventArgs e)
{
if (this.IsPostBack)
{
if (ScriptManager1.AsyncPostBackSourceElementID.StartsWith("ctl00$MainContent$calc") && ScriptManager1.AsyncPostBackSourceElementID.EndsWith("$btnRemoveCalculationFromField"))
{
//do something on the postback
}
else if (ScriptManager1.AsyncPostBackSourceElementID.StartsWith("ctl00$MainContent$calc") && (ScriptManager1.AsyncPostBackSourceElementID.EndsWith("$btnMoveCalculationUp") || ScriptManager1.AsyncPostBackSourceElementID.EndsWith("$btnMoveCalculationDown")))
{
//do something on the postback
}
}
foreach (Calculation calc in calculationCollection)
{
AssignedFieldCalculation asCalc = AssignedFieldCalculation.LoadControl(calc);
asCalc.ID = "calc" + calc.UniqueXKey;
pnlFieldCalculations.Controls.Add(asCalc);
foreach (Control ct in asCalc.Controls)
{
if (ct.ID == "btnMoveCalculationDown" || ct.ID == "btnMoveCalculationUp" || ct.ID == "btnRemoveCalculationFromField")
{
ScriptManager1.RegisterAsyncPostBackControl(ct);
}
}
}
}
A few things to note:
You need to make each control ID unique when adding it to the asp:Panel (called pnlFieldCalculations).
The LoadControl method allows you to pass initial arguments

Programmatically change background colour of some text

I have implemented master pages using this example How to implement a status bar in an ASP.NET application?. I have a property on my SiteMaster.cs inherited MasterPage called Environment. On my MasterPage.master I have this code:
<body>
<form id="frmMaster" runat="server">
<.. some content removed for brevity ...>
Environment: <%= this.Environment %>
</form>
</body>
What I would like to do is evaluate this.Environment and if it is "LIVE" then colour the background of this.Environment text red, and if it's "TEST" colour it yellow. How would I do this?
UPDATE I've just added this code to MasterPage.master
protected void Page_Load(object sender, EventArgs e)
{
lblEnvironment.Text = this.Environment;
if (this.Environment == "LIVE")
{
lblEnvironment.BackColor = System.Drawing.Color.Red;
}
}
The page loads, but the text does not get set, it's blank! Also the old text, that was populated is now blank too (I left the old code there for now). I also get a warning in Visual Studio:
'ASP.masterpage_master.Page_Load(object,
System.EventArgs)' hides inherited
member 'SiteMaster.Page_Load(object,
System.EventArgs)'. Use the new
keyword if hiding was intended.
UPDATE2: This is what I have in SiteMaster.cs
using System;
using System.Web.UI;
public class SiteMaster : MasterPage
{
public string StatusText { get; set; }
public string StatusTime { get; set; }
public string Environment { get; set; }
protected virtual void Page_Load(object sender, EventArgs e)
{
if (!this.IsPostBack)
{
if (Session["status"] != null)
{
this.StatusText = Session["status"].ToString();
this.StatusTime = Session["statusTime"].ToString();
}
this.Environment = Session["environment"].ToString();
}
}
}
Instead of using the <%= syntax to print out the environment (this is using Response.Write), consider using a server control like a Literal or a Label. As you want to change the background colour, this suggests styling (CSS), so a Label would be appropriate.
(A Literal is just a text placeholder and renders no HTML, whereas a Label (usually) renders the text inside <span> tags.)
So I would change your master page markup to
Environment: <asp:Label ID="environmentLabel" runat="server" />
In the code-behind, set the Text property of environmentLabel to this.Environment. At the same time, test the value of the evironment, and set the BackColor property of the label as appropriate (or apply a CSS class).
UPDATE:
For a master page, you just need one class, which will inherit from System.Web.UI.MasterPage. If you create this in Visual Studio and call it SiteMaster, you'll get 3 files:
SiteMaster.Master (the markup)
SiteMaster.Master.cs (the code-behind)
SiteMaster.Master.designer.cs (automatically generated/updated)
In the SiteMaster.Master file, you'll want something like this:
<%# Master Language="C#" AutoEventWireup="true" CodeBehind="SiteMaster.master.cs" Inherits="WebApplication1.SiteMaster" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<asp:ContentPlaceHolder ID="head" runat="server">
</asp:ContentPlaceHolder>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Label ID="environmentLabel" runat="server" />
<asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server" />
</div>
</form>
</body>
</html>
In SiteMaster.Master.cs, you'll need something like this:
using System;
namespace WebApplication1
{
public partial class SiteMaster : System.Web.UI.MasterPage
{
protected void Page_Load(object sender, EventArgs e)
{
this.environmentLabel.Text = "environment";
this.environmentLabel.BackColor = System.Drawing.Color.Red;
}
}
}
As the environment label is on the master page, any normal page (ASPX) using this master page will get the label displayed. Every time a page is loaded, the Page_Load event in SiteMaster.Master.cs will be called, and the text will be updated. You don't need to define the MasterPage class yourself, that's provided by the .NET framework.
You may want to improve this Page_Load method, either by using ViewState and therefore only setting the text if you're not doing a PostBack, or by disabling ViewState on the environmentLabel control.
Finally, you'll have one or more ASPX pages in your site, with something like this at the top of the markup:
<%# Page Title="" Language="C#" MasterPageFile="~/SiteMaster.Master" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="WebApplication1.WebForm1" %>
something like this..
var preTag = #" <font style=""background:yellow;color:#ff0000;font-weight:600;""><b>";
var postTag = " </b></font>";
Environment: <%= ((this.Environment=="LIVE") ? (preTag + this.Environment + postTag) : this.Environment) %>
You can also move the code from Page_Load to Page_PreRender in MasterPage.master and it should work.. it was blank because MasterPage.master Page_Load overwritten the Page_Load of SiteMaster.Master thus Environment was never assigned.

Categories

Resources