I have written an ASP.NET server control.
View state works perfectly, but when I'm trying to get a value of a control on my custom control with its public instant method, it brings me an exception that there are not control with that ID.
If you want to get the values from your custom control, you have to register your controls in OnInit event.
//Register your controls
protected override void OnInit(EventArgs e) {
var controlName = (Type)LoadControl("~/path.ascx");
controlName.ID = "YOU_MUST_SET_AN_ID";
placeholder.Controls.Add(controlName);
}
//get your controls (add the following in any method you like)
var controlNameCtrl = (Type)placeholder.FindControl("CONTROLID");
var propertyValue = controlNameCtrl.PropertyName;
When you create a custom control, the page that onward identifies the custom control as one entity and you do not get direct access to individual controls in your custom control.
To get the property value of individual elements of custom control, you should define the properties in your custom control which in turn wraps the individual control inside your custom control.
However, you can always get the value of contained control in the user control itself (Not in the page on which it is placed but in the control code itself.). You can also write events in your custom control to make it interact.
Related
I have a aspx page which has five panels. Each panel has a usercontrol in it. The user controls on all the five panels are the same. The user control in the first panel is to gather data for primary members and the rest are used for secondary members. I use ">" and "<" custom buttons to move from one panel to another. Whenever I move from the primary panel to secondary I wan to hide two textboxes in the usercontrol. When they move back to the primary panel, those textboxes should reappear. Since the buttons are in the parent page, please let me know how to do it. I believe creating an event in the usercontrol and accessing it from parent page may work. But not sure how to do it. Or please let me know any other methods.
Thanks
You need not create an event in the user controls for this.
All that you need is to create a public property on the user control, that you can set when you use the user control.
Since you have not provided any code, I will just give a sample.
public partial class MyWidget: System.Web.UI.UserControl
{
private bool showPrimary;
public bool ShowPrimary
{
get { return showPrimary; }
set
{
showPrimary = value;
txtPK1.Visible = value;
txtPK2.Visible = value;
}
}
}
Then you set it when you call it as follows:
Main Panel:
<uc1:MyWidget ID="MyWidget1" ShowPrimary="true" runat="server" />
Secondary Panel:
<uc1:MyWidget ID="MyWidget1" ShowPrimary="false" runat="server" />
I don't understand, the buttons > and < are in the page to advance to the next/previous control. Then you just have to handle their click event in the page and switch visibility of the UserControls.
If you don't know how to control visibility of controls inside of UserControls from the page:
Use properties in the UserControl, for example PrimaryMode. There you can hide/show the TextBoxes accordingly. You can call these properties from the page. PrimaryMode could be of type bool or a custom enum type(if you want to provide multiple display-modes).
I'm aware this question has been asked many times before but I suspect I have a unique scenario.
I'm loading a Child Control (ASCX) and setting a Property on that Control. This works perfectly fine until postback where the property is null.
Herewith the First Class which loads the ChildControl :
protected override void CreateChildControls()
{
MyUserControl control = (MyUserControl)Page.LoadControl(_ascxPath);
control.MyProperty = base.MyProperty
Controls.Add(control);
}
Then, on my Child Control I've got the following code:
public partial class MyUserControl : UserControl
{
public MyType MyProperty { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
//Exception on next line because Property is null (only on postback)
var somevalue = MyProperty.SubProperty;
Ok. Let me try to explain it.
1. Once page is created, you get full page lifecycle
2. You click on some control to create user control, and you get it
3. Now you are entering value to this control, and getting postback
4. On server side postback is handled, but as you can see viewstate actions appear as soon as page is loaded.
One of main purposes of viewstate is handling control events, to see if they are changed, or save their states or something else.
5. If on the moment, when viewstate is loaded you control is still not constructed, then all it's events and values would be ignored.
Solution either make it static control and just hide it, either create it before viewstate actions started.
You need to add the control and set properties in the Page_Init event, other wise you will lose the properties value.
In Microsoft explanations about ASP.NET page life cycle, it is written that dynamically created controls must be created in PreInit.
It worked for me.
Here is my main page :
protected global::System.Web.UI.HtmlControls.HtmlGenericControl FiltersZone;
(. . .)
protected override void OnPreInit(EventArgs e)
{
base.OnPreInit(e);
FiltersZone.Controls.Add(new PlanningFiltersSurgeonWeb());
}
This dynamically created ".ascx" control contains an hidden field :
<input id="hidTxtPaint" type="hidden" name="hidTxtPaint" runat="server" />
I am now able to retrieve its value from within dynamically created ASCX control Page_Load event, after a "submit" or a "__dopostback('hidTxtPaint')" initiated from JavaScript.
On the other hand, the hidden field's value is always empty after a POST if its parent ".ascx" control is added in main page's Page_Load event.
I have a user control nested in a repeater.
Inside my user control I have another repeater and in that I have a panel.
I am trying to override the LoadViewState event of my user control and dynamically add controls to the panel. I want to do it in the LoadViewState so that the dynamic controls get added before the viewstate gets loaded, so they retain their values after post backs.
For some reason the LoadViewState event on the user control (ascx) is not firing. Is there some way to force it to fire, or is there another method I could use? I have ruled out the user controls repeater databind event, because I need it to work even if data binding isn't happening and I can't do it on the repeaters item created event either because the child panel and inner html doesn't exist yet.
LoadViewState isn't the appropriate place for adding child controls. For dynamically adding controls within a user control, you'll want to look at the CreateChildControls method.
It's not firing a LoadViewState event because you need to save at least one value in the ViewState to have the event fire.
I think I had a similar problem with some dynamically created children user controls. LoadViewState wasn't called in postbacks even if I was able to access their ViewState when creating them first. SaveViewState seemed to be also called correctly. It ended that the children ViewState was not really usable (without this resulting in an exception) in the page Init event before they were fully initializated, and this happened only when the controls were added to the parent. After having ensured this, the children ViewState was correctly persisted across postbacks.
// Belongs to a Page. If you create the children control in the
// Load event in you can also access the page ViewState
protected void Page_Init(object sender, EventArgs e)
{
if (!IsPostBack)
{
for (int it = 0; it < 5; it++)
{
ChildControl child = LoadControl("ChildControl.ascx")
as ChildControl;
child.ParentPage = this;
TabPanel tab = tabContainer.FindControl("TabPanel" + it)
as TabPanel;
// Ensure to add the child control to its parent before
// accessing its ViewState!
tab.Controls.Add(child); // <---
string caption = "Ciao" + it;
child.Caption = caption; // Here we access the ViewState
tab.HeaderText = caption;
tab.Visible = true;
_Children.Add(child);
}
}
[...]
}
// Belongs to ChildControl
public string Caption
{
get { return ViewState["Caption"] as string; }
internal set { this.ViewState["Caption"] = value; }
}
I'm trying to create a custom server control (WebControl) with a text box.
I add asp.net textbox to the custom control in CreateChildControls override. In OnInit override I add event handler to TextBox.TextChanged.
Everything works, except that TextChanged never fires. I looked at viewstate and it looks like my textbox never saves its Text property in the viewstate. I've tried to set Text in various places, including constructor, but nothing works.
How can I get TextBox dynamically added to WebControl to save it's Text in viewstate and get TextChanged event to fire?
I would greatly appreciate an example of WebControl code behind with TextBox being added dynamically and TextChanged event being fired.
The dynamically created control must be created again in each post back, (the pageInit event is the better option) for the event to be fired.
BTW, if you want the TextChanged event to generate a postback you must also set the AutoPostback of the control to true.
fixed it. dynamic control must be created and added in Init event. It must be assigned an ID without special ASP.NET symbols ('$' or ':' inside custom ID will break things). All properties must be assigned after control is added to the controls tree.
here's a working example for Page codebehind:
private readonly TextBox _textBoxTest = new TextBox();
protected void Page_Init( object sender, EventArgs e )
{
this.form1.Controls.Add( _textBoxTest );
_textBoxTest.Text = "TestBoxTest";
_textBoxTest.ID = "TestBoxTestId";
_textBoxTest.TextChanged += this._textBoxTest_TextChanged;
}
void _textBoxTest_TextChanged( object sender, EventArgs e )
{
_textBoxTest.Text = "Worked";
}
for WebControl place init code in OnInit override
This will help you out. In short, you need to handle the viewstate for your Dynamically added control on your own.
Ok time to show my complete lack of knowladge for all things web forms but here goes. I am extending the Panel control and OnPreRender sticking some additional controls inside of it (lets just say 1 textbox for simplicity). From here I am just letting the Panels Render method do its thing.
The issue I am having is that obviously every time this control is rerendered it is just sticks that same TextBox in the panel again with the value I am coding in the OnPreRender method. Now I dont actually want to repopulate the panel every time,
I want to stick the textbox contorl in there on first load and have them reloaded from the control/viewstate caches. In this case with my example of just sticking a single textbox in the panel, if the value of the textbox changes and a postback occurs I want that value to to remain the changed value.
Really basic webforms stuff I know, but I have never had to create custom controls in my time. ANy help appreciated.
Chris.
You need to (re)create the child control (the textbox) in OnInit - so that it's there when LoadViewState and ProcessPostBackData is called.
See the server control lifecycle for more info.
Dynamic controls in ASP.NET are tricky, especially if you are new to webforms and the page lifecycle. If you can avoid dynamic controls, do so. Use controlName.Visible=false, and other tricks instead.
If you must then read this article. Rule of thumb,add controls early in the page life cycle, reference them later in the page lifecycle. PreRender is almost the very end, an uncommon place to be adding and using controls.
Not sure if this applies to all versions of .Net, (I think 2.0 or later) but there is a method called CreateChildControls that isn't really a part of the lifecycle exactly, it's basically called anytime the EnsureChildControls method is called. By default it is called before PreRender if it's not a postback. So basically your code would look like this:
public class SomeControl : WebControl, INamingContainer
{
private TextBox someTextBox;
protected override void CreateChildControls()
{
base.CreateChildControls();
someTextBox= new TextBox();
someTextBox.ID = "tbxMain";
Controls.Add(textboxToCheck);
}
}
Now the part to not is that unless you call EnsureChildControls, you can't be 100% sure that the controls exist before the Public Properties on your control are filled by the ViewState load. What does this mean? Well take the code from before and add a property for the CssClass:
public class SomeControl : WebControl, INamingContainer
{
private TextBox someTextBox;
protected override void CreateChildControls()
{
base.CreateChildControls();
someTextBox= new TextBox();
someTextBox.ID = "tbxMain";
Controls.Add(textboxToCheck);
}
public String CssClass { get; set; }
}
In CreateChildControls you won't want this:
someTextBox.CssClass = CssClass;
Since there is no way to be sure the control exists yet. There's a couple ways you can handle this:
public String CssClass
{
get
{
EnsureChildControls();
return someTextbox.CssClass;
}
set
{
EnsureChildControls();
someTextbox.CssClass = value;
}
In this example I am calling EnsureChildControls (Assuming you are setting the CssValue on the textbox in the CreateChildControls method) and setting or getting from the textbox.
Another way is putting anything that depends on the control's public properties in the OnPreRender method:
protected override void OnPreRender(EventArgs e)
{
someTextbox.CssClass = CssClass;
}
Thus avoiding the mess of worrying about the property being filled already during the ViewState load.
One Note:
The use of INamingContainer can be important. Basically all that does is makes sure the controls on the parent control have an id that is unique on the page by applying the parent's name (And maybe more) to the id. Basically if the parent ID is Parent and the child control ID is Child the ID might show up as Parent_Child. This will solve problems with ViewState not populating the properties correctly or not at all.
Inside your code you will need to manage the restore of viewstate information should you need the services of viewstate.
A good example here is this View State example by Microsoft. There are a few other items referenced in the code sample, but it should get you along the right path.