My page contains several web user controls. Those controls contains other child controls, and those contains more child controls and so on. From my page, I want to be able to access those controls, like I do with other public classes: uc1.uc1_child1.uc1_child1_child1.Update();
(I do know about the FindControl method, and thats what Im currently using. It's however not type safe, and I need to lookup the names of the controls all the time to be on safe side. Much more time consuming than intellisense)
If you create a public property on your usercontrol for each of the usercontrols it contains, that should work.
eg
public SpecificUserControlType ContainedUserControl
{
get
{
return this.uc1_child;
}
}
Related
How dan I dynamically create some public properties on a custom webcontrol.
For example, web control has 5 TextBox controls. I need a public property for each TextBox control to be able to set a specific property of the TextBox control.
I want to be able to loop the controls in the webcontrol and create a public property for each TextBox control.
any ideas?
Edited:
If the child-controls are present at Design-Time then you need to explain why you want to dynamically add properties to access the control members--unless there is a good reason it just sounds like a poor design.
Here's my suggestion:
Leave your controls as Friend or Private -- don't expose them directly (it leads to tight-coupling and gets nasty over time).
Expose a new public property that gets/sets the corresponding property on 1x of your controls; so if you want to set .Text on 5x TextBoxes you'll have 5x properties.
Be done with it.
If you're trying to be clever by dynamically adding them, then it's a good intention that will lead to poor results. Just remember: KISS (Keep it simple, stupid!).
You could create a property like this
private TextBox[] textBoxes; //declared as a class member variable
public TextBox[] TextBoxes
{
get
{
if (textBoxes == null)
{
textBoxes =(from ctrl in this.Controls.OfType<Control>()
where ctrl is TextBox
select (TextBox)ctrl).ToArray();
}
return textBoxes;
}
}
Exposing the controls contained in a WebContol (or any class for that matter) is not a good design as it makes your code brittle and hard to maintain. You should put code that directly manipulates the TextBoxes inside the WebControl.
I have some control. I add one instance of this control to every Page in OnInit event and I want to access this control in other places in this way: Sample.Current
public class Sample : Control
{
public static Sample Current
{
get
{
// ???
}
}
}
Can you tell me what is the best way to do this property implementation?
It would be good to have a bit more detail - what is this class' purpose? But I'll attempt to help anyway:
You'll be able to access that control from within code on the page , if it's referenced in the code and not added dynamically somehow at runtime. ie if it's a variable of the page declared like:
Sample ctrl = new Sample();
Then later you can reference it using ctrl.Current in your code.
FYI - if you want a place to reference classes and variables for a page's lifecycle, you may want to check out HttpContext.Current.Items http://www.mikeduncan.com/3-hot-uses-for-httpcontextcurrentitems-they-wont-tell-you-about/ It's like a session bag that only exists for a single page request - for example if you have a class that holds information about a user that you need to access many times from many different controls on the page, you could just stick that class into the Items collection and then reference it from any code that runs on your page.
HTH,
Lance
When a control is added to an UpdatePanel, it can still be accessed from the code behind of the containing page. How is this achieved? Can custom control developers do the same?
In other words, if I develop a template control using the ITemplate Interface, is there a way to wire it up (like the UpdatePanel seems to) so that any controls contained within (declaratively) can be accessed from the containing page also?
You can add a TemplateInstanceAttribute on your ITemplate property to achieve this, it has the effect of promoting the controls to page level:
[TemplateInstance(TemplateInstance.Single)]
public ITemplate AnonymousTemplate {
get { ... }
set { ... }
}
From MSDN:
The TemplateInstanceAttribute class allows you to mark a template property as one that allows single or multiple instantiations. A template that only allows a single instantiation can have the controls that are contained inside of it referenced. The ZoneTemplate property is an example of a property that can be instantiated only one time.
I am creating a WebUserControl in ASP.net and want to be able to access elements of that control later. When I access them though I am trying to access them together. For example, adding a CheckBox and a table to a control and then finding the CheckBox, checking whether it has been ticked and if it has been ticked, get the values from the TextBoxes.
I currently have everything loading on the page from the custom controls, but when iterating through the controls on the page, there doesn't appear to be a control of my WebUserControl type. All of the controls are there on the page, but they exist as seperate ASP.net controls.
Am I thinking about this wrong? Is there a better way to do this?
I'm not sure this is explained very well, please feel free to ask clarifying questions.
You need to expose the user controls functionality by making public properties or functions to make it do what you need or act like you want. So for example in your case you could have a property in your user control like (you could also do a function):
public List<string> SomeValues
{
get
{
// return null if checkbox is not checked, you could just as easily return an empty list.
List<string> lst = null;
if (yourCheckBox.Checked)
{
lst = new List<string>();
// You could have something that iterates and find your controls, remember you
// are running this within your user control so you can access all it's controls.
lst.Add(yourTextBox1.Text);
lst.Add(yourTextBox2.Text);
lst.Add(yourTextBox3.Text);
// etc...
}
return lst;
}
}
Then in your page you can access your user control and call this property to get the values:
// assuming you defined your usercontrol with the 'yourUserControl' ID
List<string> lst = yourUserControl.SomeValues;
The key is to just expose what you want IN your user control so whatever is using it doesn't need to know about it's details or implementation. You should be able to just use it as you would any other control.
I've created some Web User Controls (.ascx files) and dropped them into Pages. The user controls have some TextBoxes in them that I'd like the Page to be able to access directly.
What's the easiest (read: least time) way to expose these TextBoxes in the user controls to the Pages containing the user controls?
The two options I know are calling myUserControl.FindControl(id) from the Pages (does this even work from the Page?), and writing properties in the user controls to expose the TextBox values.
Neither seem ideal. FindControl() requires the Page know the IDs of the TextBoxes in the user controls, thereby breaking encapsulation and adding hard-coded strings, and writing a bunch of properties in the user controls will be very time consuming given the number of TextBoxes in these user controls.
There's no way to declare these TextBoxes in my user controls be public instead of protected?
(Setting aside the obvious comments about the fact that what you're describing is essentially the opposite of best practice...)
If you are using a Web Application type project, you should have a designer.cs file for each UserControl. That contains the declaration of each child control, so you can change the access modifier to public.
If you are using a Web Site type project, you should probably convert to Web Application. According to Microsoft (and backed up by experience), the Web Site type is not intended for use when you plan to write extensive code which spans beyond a single code-behind.
If I have to do this I will write a public property that exposes the controls. However there is usually a way to rewrite the information such that you don't need to expose the internal controls. If all you need is the value, create a property that returns the value. If you need client ids, perhaps creating a client object that exposes values or events will solve the issue. Remember, once you make it public, you are exposes a contract and changing that contract will almost always be painful.
You can expose it as a property from the code behind. You'll really only be able to access it's properties from code, not from the ASP.Net designer though. This is an example in vb that exposes a DropDownList on a user control (and, it may not be a best practice but it certainly beats writing code to expose every property on the child controls):
''' <summary>
''' This is the exposed DropDownList for this control.
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public ReadOnly Property DrowDownList() As DropDownList
Get
Return ddControlList
End Get
End Property
Why not give your user control a collection of TextBoxes, expose the collection as a property, and in your Init() method, just add all your textboxes to the collection?
That way, you have a collection that you can search by ID if you ever need to, without relying on any page logic, and you only have to expose one property. If you make your own collection class for it, you could even program in a couple of handy methods for accessing the textboxes the way you need to.
Derive all of your Web User Controls from a common base class and expose this functionality as a public method (or methods). Your base class can derive from UserControl (the way an .ascx normally would) and your controls in turn derive from it.
Then, even if using reflection seems like a bit of work, you're only doing it once. If the textboxes are dynamic and you want to avoid hardcoding things, this would be the way to go.
So, if you need to just get the value of the text box by id from a parent, you can add something like the following to your base class:
public string GetTextboxValue(string id)
{
string textValue = string.Empty;
Control ctl = FindControl(id);
if (ctl.GetType() == typeof(TextBox))
textValue = ((TextBox)ctl).Text;
return textValue;
}
I'd say to go this route vs. the previous suggestion of making the TextBox public since you really only want to read the text value from the parent and not expose the entire object as read/write.