Multiple instances of server control attached programmatically not appearing? - c#

In the code behind of my page I want to attach a label in multiple places. To achieve this and avoid creating mutliple instances of the same label I've tried:
Label lblNone = new Label();
lblNone.Text = "<br/> None. <br/>";
Master.mainContent.Controls.Add(lblNone);
Master.mainContent.Controls.Add(lblNone);
Master.mainContent.Controls.Add(lblNone);
For some reason I only see 1 instance of the "None." on my page?
Why is this?

You have no option.. you need to create one instance of Label for each control you want to see in the screen.
This is because of the behavior of the ControlCollection class.
it will not allow multiple adds of the same "reference".
When you add a control to one ControlCollection it is automatically removed from the previous so, even if you were adding your label to different ControlCollections it wouldn't work.
PS: By ControlCollection I mean the type of the property Master.mainContent.Controls

You might find it easier to create a method for this as so: -
protected void Page_Load(object sender, EventArgs e)
{
this.Controls.Add(CreateLiteral("text"));
this.Controls.Add(CreateLiteral("text"));
this.Controls.Add(CreateLiteral("text"));
}
private Literal CreateLiteral(string Content)
{
Literal L = new Literal();
L.Text = Content;
return L;
}
Thanks,
Phil.

Related

Asp.NET server control events not firing

Thanks for all who reads. I have a code issue that has been discussed many times on stackoverflow, but I can't make the provided solutions work.
It's about server control that contain other controls and I can't fire their events.
My issue is simple, i need to add any numbers ok LinButton into my server control. this is my code:
protected override void CreateChildControls()
{
for (int i = 0; i < IndiceValue; i++)
{
LinkButton imageTemp = new LinkButton() { CommandName = String.Format("{1}_{0}", CommandNames, i), Text = i.ToString(), ID = Guid.NewGuid().ToString()};
imageTemp.Click += ImageTempOnClick;
this.Controls.Add(imageTemp);
}
base.CreateChildControls();
}
I have a custom event in my control:
public delegate void IndiceFiabiliteCommand(object sender, IndiceFiabiliteCommandEventArg e);
public event IndiceFiabiliteCommand Command;
And theorically, when any of the LinkButton is clicked, I want the user to be warn that any of the LinkButton has been clicked. I give him all the needed infos but i don't think this part is the problem.
Last thing to know is that I implement INamingContainer and I tried to implement both, IPostBackDataHandler and IPostBackEventHandler but it didn't worked.
I hope it's understandable enough
thanks!
The problem is ID = Guid.NewGuid().ToString()
You cannot have dynamically created control with dynamic id. Change the code to
... i.ToString(), ID = i.ToString()
Basically, dynamic control's ID must be same as the ID originally created.
Otherwise, new control is created on every post-back, and it cannot find the control which causes the post-back.
FYI: if you need to catch an event, I would like to suggest to use CompositeControl which already have INamingContainer.
Note: it is just what I found based on your code; it might be other issue too.

Use controls that are created at runtime

I am creating a textbox and a checkbox at runtime:
TextBox tb = new TextBox();
tb.Name = "txtPassword";
tb.PasswordChar = '*';
CheckBox cb = new CheckBox();
cb.Text = "Show Password";
cb.Name = "cbShowPassword";
cb.CheckedChanged += new EventHandler(cbShowPassword_CheckedChanged);
And I want to mask or unmask the password according to the checkbox:
private void cbShowPassword_CheckedChanged(object sender, EventArgs e)
{
txtPassword.PasswordChar = cbShowPassword.Checked ? '\0' : '*';
}
The problem is, it doesn't recognize txtPassword and cbShowPassword under cbShowPassword_CheckedChanged, since it is created in the code.
How can I make it work?
As it stands, you use a local variable tb in the method in which you instantiate the control. You can use that variable only in the method that instantiates the control. The fact that you gave the control a name does not mean that there is a variable defined named txtPassword.
You could continue this way, and dynamically look the control up from any other methods that wish to refer to it. However, that makes life harder than it needs to be. What you really want is a variable that refers to the control.
So, create a private member field of your class named txtPassword. Create the control like this:
txtPassword = new TextBox();
txtPassword.PasswordChar = '*';
....
To be really clear, txtPassword is a private member of your class, not a local variable.
Then you will be able to refer to it from other methods. Is there is a possibility that it might not have been created, test txtPassword against null.
Obviously you use the same technique for any other dynamically created controls.
I think you are mixing something up.
Did you add the controls to the parent form/controls?
Does the event fire ? (put a break point in there)
Try to use them as members instead of the name property and access this.cb and this.tb
You could use your form to find any Child controls that matches your newly created textboxes and Checkboxes.
http://msdn.microsoft.com/en-us/library/system.windows.forms.control.controls(v=vs.110).aspx
Else you could set a reference to this objects in a property on the Form.

How to change icon and text to a ApplicationBarIconButton?

I want to make my click event change an ApplicationBarIconButton. My ApplicationBarIconButton looks like this:
<shell:ApplicationBarIconButton x:Name="driveAction" Click="drive_click" IconUri="/img/car.png" Text="kör" />
I want the IconUri to change from /img/car.png to ex. /img/car-stop.png and the text value from kör to passagera. I tried the function below, but it only causes my app to shut down.
private void drive_click(object sender, EventArgs e)
{
this.driveAction.Text = "passagera";
this.driveAction.Source = "/img/car-stop.png";
}
What is wrong? Why doesn't this work?
The default ApplicationBar requires you to access the buttons through the ApplicationBar object. To accomplish this you must know the index of the button that you want to change
private const int DriveButtonIndex = 0;
private void drive_click(object sender, EventArgs e)
{
var button = (ApplicationBarIconButton)ApplicationBar.Buttons[DriveButtonIndex];
button.IconUri = new Uri("/img/car-stop.png", UriKind.Relative);
button.Text = "passagera";
}
There are a few custom ApplicationBars that allow you to name your buttons. But I've found that the above solution always works for me.
Get it directly from the application bar list -
ApplicationBar.Buttons[0].Text = "passagera";
ApplicationBar.Buttons[0].Source = "/img/car-stop.png";
You could also query the list of buttons for a specific icon as a more tenable long-term solution, but if you only have one button and that's not going to change, this works.
Because the ApplicationBarIconButton is actually a native control and not a true XAML object you cannot refer to it by name.
You can refer to it by index if create in XAML. Alternatively you could create it in code and then you can maintain a named reference you can use.

Ensuring unique ID attribute for elements within ScriptControl

I'm creating a control based on ScriptControl, and I'm overriding the Render method like this:
protected override void Render(HtmlTextWriter writer)
{
RenderBeginTag(writer);
writer.RenderBeginTag(HtmlTextWriterTag.Div);
writer.Write("This is a test.");
writer.RenderEndTag();
RenderEndTag(writer);
}
My question is, what if I want to assign the div an ID attribute and have it be unique on the page, even if there are mulitple instances of my control?
I've seen other people's code that does this:
writer.AddAttribute(HtmlTextWriterAttribute.Id, this.ClientID + "_divTest");
That will prevent naming conflicts between instances of my control, but what if I've already created a div elsewhere on the page that coincidentally has the same ID?
I've also heard about implementing INamingContainer. Would that apply here? How could I use it?
UPDATE:
I've worked around this by overriding CreateChildControls and adding actual controls, as opposed to rendering HTML directly. In that case INamingContainer does its job. However, I'm still curious if there's a way to solve my original problem (unique IDs for directly rendered elements).
INamingController is a marker interface. Implementing it will guarantee you unique ids for each instance of your control.
http://msdn.microsoft.com/en-us/library/system.web.ui.inamingcontainer.aspx
public class MyScriptControl: ScriptControl, INamingContainer {
}
You won't want to create instances of controls just to get unique Ids, there's useless overhead/complexity in that approach. The Control.ID property may not be unique, but the Control.ClientID property will be unique. Therefore
writer.AddAttribute(HtmlTextWriterAttribute.Id, this.ClientID + "_divTest");
that attribute has to be unique unless you use the suffix "_divTest" twice in your custom control.
I am tried to realize your issue:
public class SC : ScriptControl
{
protected override IEnumerable<ScriptDescriptor> GetScriptDescriptors()
{
return null;
}
protected override IEnumerable<ScriptReference> GetScriptReferences()
{
return null;
}
}
//... Page code
protected void Page_PreRender(object sender, EventArgs e)
{
var sc = new SC();
var sc1 = new SC();
Page.Form.Controls.Add(sc);
Page.Form.Controls.Add(sc1);
}
But sc and sc1 have different ClientID. So it is not ASP.NET issue. Look over your realization. May be you generate ids for divs before adding ScriptControls to Page, or may be you try to create 2 divs in the scope of one ScriptControl, or may be you create ScriptConrol2 dynamicly on async-posback and it have the same id as ScriptControl1, that not added dynamicly on postback.

Dynamically adding Content blocks to Masterpage fails after Master.FindControl

I've encountered an odd problem that doesn't make any sense to me. I am trying to dynamically set up MasterPage Content controls on a page. I have it working nicely with the following code:
protected override void OnPreInit(EventArgs e)
{
base.OnPreInit(e);
MasterPageFile = "~/MasterPages/Default.master";
string existantContentPlaceHolderID = "ContentPlaceHolder1";
string nonExistantContentPlaceHolderID = "foo";
//Control c = Master.FindControl(existantContentPlaceHolderID);
//Control c1 = Master.FindControl(nonExistantContentPlaceHolderID);
TextBox t = new TextBox
{
Text = "Text"
};
ITemplate iTemplate = new GenericITemplate(container => container.Controls.Add(t));
AddContentTemplate(existantContentPlaceHolderID, iTemplate);
}
public delegate void InstantiateTemplateDelegate(Control container);
public class GenericITemplate : ITemplate
{
private readonly InstantiateTemplateDelegate m_instantiateTemplate;
public void InstantiateIn(Control container)
{
m_instantiateTemplate(container);
}
public GenericITemplate(InstantiateTemplateDelegate instantiateTemplate)
{
m_instantiateTemplate = instantiateTemplate;
}
}
This works great, except I want to be able to double-check that the contentPlaceHolderIDs exist on the MasterPage before calling AddContentTemplate as the Page will throw an error if you add a Content control that points to a non-existing ContentPlaceHolder.
The problem I am having is that in the above example when I call one of the commented Master.FindControl lines, the TextBox no longer renders.
Does anyone have any ideas why this might be... I cannot makes heads or tails of what is going on.
Thanks,
Max
The problem is that AddContentTemplate just records its parameters in a hashtable ready to be combined with the master page instance when it is created. Calling it after the master page has been created won't do anything, and reading the Master property causes the master page to be created.
The best way I can see around this is to create a separate instance of the master page with LoadControl, which you can inspect without affecting the page's own Master property...
MasterPage testMaster = (MasterPage) LoadControl( MasterPageFile );
Control c = testMaster.FindControl(existantContentPlaceHolderID);
There's some overhead in creating a second instance, but it's not immediately obvious to me whether it will be worth worrying about.

Categories

Resources