I have an UpdatePanel.
and I have a PlaceHolder inside this UpdatePanel.
There is a number of UserControls. One of them will be loaded dynamically,
according to some selections.
Control mycontrol = this.Page.LoadControl("myusercontrol.ascx");
myplaceholder.Controls.Add(mycontrol);
after loading a specific UserControl, I wanted to get the text written in
a TextBox that is in the loaded UserControl from the Parent page.
TextBox mytextbox = (TextBox) Page.FindControl("myusercontrol")
.FindControl("mytextbox");
The problem was the text is always empty !
What am I missing ?
I appreciate your help.
You should load your UserControl overriding OnInit as mentioned before. And why were you looking entire page to find the UserControl? You can use PlaceHolder.Controls...
This how I got it work
protected override void OnInit(EventArgs e)
{
Control userControl = this.Page.LoadControl("WebUserControl.ascx");
testPlaceHolder.Controls.Add(userControl);
userControl.ID="id";
base.OnInit(e);
}
protected void testButton_Click(object sender, EventArgs e)
{
Control testUserControl = (Control)testPlaceHolder.Controls[0];
//Control testUserControl=(Control)testPlaceHolder.FindControl("id");
TextBox mytextbox = (TextBox)testUserControl.FindControl("testTextBox");
testButton.Text = mytextbox.Text;
}
When you say that the text is always empty, do mean the TextBox object is null or literally the .Text of the textbox is empty?
Remember that in web applications you have to post back to the server to refresh results and update controls among other things.
Try posting back to the server and seeing if that helps.
Have you considered adding a property to your user control to return the text?
eg:
public class YourControl : UserControl
{
public string Text
{
get
{
return this.TextBox1.Text;
}
}
}
Usually, User Controls are used for encapsulation - you wrap up all the details of controls, behaviour etc in a UC so other code doesn't have to deal with it.
By referring to controls within the UC directly - by name or ID - you're breaking the model. Can I suggest you don't do this, instead if you need to get information from the UC you add a property, event or method to it that the container can call.
That way if you need to change the UC - control names, types, styles, or additional logic is used later - you only need to change that property/event/method in the UC, not in the (for example) 100 places it might be used in the code.
If you could let us know why you need this information or more specific details about the example, perhaps we can suggest some code to implement this.
So, what should I do ?
Just get the posted values manually.
Request.Form[yourcondeol.UniqueID]
by debugging this you can see all the posted data.
Request.Form
Related
I have a UserControl that is dynamically added to a FlowLayoutPanel. In that same UserControl I have a button to remove itself if the user wants it, obviously at runtime. To eliminate I mean not only to eliminate that tight button, but also the full UserControl that contains the button.
The code of when the UserControl are added dynamically at the moment is as follows:
private void agregaUC() {
UserControl1 UC = new UserControl1();
aux += 1;
UC.Tag = aux.ToString();
flowLayoutPanel2.Controls.Add(UC);
}
The code to eliminate this is on the side of the form, that is, where the UserControl are being added. The button event to remove the UserControl is thrown by code through the operator + =, then there I write the suggestions that you give me.
EDIT: Based on the sample of code you've added, I've modified the below code to work better with what you are looking for. You need to find out how to access the Tag of the control you're trying to remove.
Since you don't have a reference, then you should make sure that the .Tag property can be found, because then you can do something like
foreach (Control c in flowLayoutPanel2.Controls) {
if (c.Tag == "Aux") {
flowLayoutPanel2.Controls.Remove(c);
c.Dispose();
break;
}
}
EDIT
Reading through all the comments everywhere, it seems like this is what's happening. There is a UserControl, inside that user control is a Button (Delete) and the button's Click event is subscribed to by the window, and it's in this event handler that we're trying to remove the UserControl from flowLayoutPanel2
Based on these assumptions, your function should look like this:
void UserControl_Delete_Click(object sender, EventArgs e)
{
Button Delete = (Button)sender;
UserControl UC = (UserControl)Delete.Parent;
flowLayoutControl2.Controls.Remove(UC);
UC.Dispose();
}
This is assuming a lot about the internal structure of everything, as I don't have the code to confirm this will work. It will get you a long ways down the path, though, and should only need a little tweaking based on the actual structure of the UserControl.
You can try something like that.
this.Parent.Controls.Remove(this);
Control.Parent Property.
Remark: Setting the Parent property value to null removes the control from the Control.ControlCollection of its current parent control.
So
this.Parent = null;
Edit
The code is intended to be called from within the user control itself.
I have a main form with some buttons, textboxes, labels, etc.
On a second form I would like to copy the text from the main forms textbox onto the second form.
Have tried:
var form = new MainScreen();
TextBox tb= form.Controls["textboxMain"] as TextBox;
textboxSecond.Text = tb.Text;
But it just causes an exception. The main screen textbox is initialised and contains text.
When I hover over form I can see all the controls are there.
What am I doing wrong?
Looking at the original code, there are two potential reasons for the NullReferenceException you are getting. First, tb is not defined in the code you provide so I am not sure what that is.
Secondly, TextBox textbox = form.Controls["textboxMain"] as TextBox can return null if the control is not found or is not a TextBox. Controls, by default, are marked with the private accessor, which leads me to suspect that form.Controls[...] will return null for private members.
While marking the controls as internal will potentially fix this issue, it's really not the best way to tackle this situation and will only lead to poor coding habits in the future. private accessors on controls are perfectly fine.
A better way to share the data between the forms would be with public properties. For example, let's say you have a TextBox on your main screen called usernameTextBox and want to expose it publicly to other forms:
public string Username
{
get { return usernameTextBox.Text; }
set { usernameTextBox.Text = value; }
}
Then all you would have to do in your code is:
var form = new MainForm();
myTextBox.Text = form.Username; // Get the username TextBox value
form.Username = myTextBox.Text; // Set the username TextBox value
The great part about this solution is that you have better control of how data is stored via properties. Your get and set actions can contain logic, set multiple values, perform validation, and various other functionality.
If you are using WPF I would recommend looking up the MVVM pattern as it allows you to do similar with object states.
PhoenixReborn is correct. The problem is that you are creating a new MainScreen, which means that new controls are created, so unless the text in your controls are initialized in the form constructor, they are going to be empty. Usually, the way to handle this is to pass the first form instance to the second form, like this:
SecondForm second = new SecondForm(this);
and in the second form:
public SecondForm (MainForm form)
{
// do something with form, like save it to a property or access it's controls
}
That way, the second form will have access to the first form's controls. You might consider making the properties you need to use public (in the designer properties pane). That way you can just do form.textboxMain.Text.
Currently I have a C# program with a windows form and then a user control template put onto the form. The user control template is really just used as a placeholder. I have a series of other controls which inherit from this user control template.
Each of those controls have navigation buttons like 'Continue' and 'Back' on them and each control knows which control needs to be loaded next. However what I need to figure out is an easier way to have variables that are global to these controls.
The only workaround I have is that I pass the form to each control when they are loaded and use variables inside of the form to read and write to. What would be the proper way to have each of these user control screens be built off of a base control which contained objects all of the controls could get to?
Sorry for the rambling nature of the post but I've been thinking about this problem all morning.
Here is some of the code:
Most of what I have written was based on hiding and showing the user controls so that content in the controls wouldn't be lost during navigation. I won't be needing to do that as eventually it will be loading the fields of data from a database.
Code for initially loading control from form click:
conTemplate1.Controls.Clear();
conInbound Inbound = new conInbound(this);
Inbound.Dock = DockStyle.Fill;
Inbound.Anchor = (AnchorStyles.Left | AnchorStyles.Top);
conTemplate1.Controls.Add(Inbound);
Code for Continue button inside of one of the controls:
if ((Parent.Controls.Count - 1) <= Parent.Controls.IndexOf(this))
{
UserControl nextControl = new conPartialClear();
nextControl.Dock = DockStyle.Fill;
Parent.Controls.Add(nextControl);
this.Hide();
Parent.Controls[Parent.Controls.IndexOf(this) + 1].Show();
}
else
{
this.Hide();
Parent.Controls[Parent.Controls.IndexOf(this) + 1].Show();
}
The best-practice for communicating from a control to a parent is to use events, and for communicating from a parent to a control is to call methods.
However, if you don't want to or can't follow this practice, here's what I would recommend.
Each UserControl has a ParentForm property that returns the Form that contains the control. If you know that the UserControl will always be attached to MyParentForm, you just cast the ParentForm and then you can access all public controls, methods, etc.
Here's what I mean:
public class conTemplate
{
public MyParentForm MyParentForm
{
get
{
return (MyParentForm)this.ParentForm;
}
}
}
This way, you can easily access any public members of MyParentForm. Your conInbound class could have code such as this.MyParentForm.GlobalSettings.etc..., and could even have access to any public controls.
I'm not totally sure I understand your problem. It sounds like you want the user control to "do something" with it's parent form. If that's the case, you may want to consider adding events to the UC and then handle them on the form itself.
Basically, for your UC's "continue", you'll have an event that's fired when it's pressed. You'll want to handle that in your form. I'm not real sure about the syntax from memory, or I'd work something out for you code-wise. But I think that's the route you'll want to take. Think of your UC like any other windows form control. If you add a button to your form, you assign it it's event method. Do the same with the UC.
I found this and thought it may be helpful. Scroll down to where it talks about UC's and events.
http://www.akadia.com/services/dotnet_user_controls.html
Hope this helps.
EDIT after new info from OP.
You could declare a global variable inside the UC of type yourForm and then set that variable to the ParentForm at run-time, if I'm understanding you correctly.
So, inside your UC Class, you could do:
private parentFormInstance;
then inside the constructor of the UC, you could set it as such:
parentFormInstance = this.ParentForm; (or whatever the property name is).
This allows you at design-time to use:
parentFormInstance.DoSomething();
without the compiler yelling at you.
Just basic advice, but if you can go back and make it easier on yourself, even if it takes some additional time re-working things, it'd be worth it. It may save you time in the long run.
I am making a form that contains a lot of User Controls, each User Control is part of the form (contains TextBox, ComboBox etc).
User will use the form to update their information.
At end of submission, I need to display the original data and the data that the user have entered.
I wonder if is possible that I can replace the input control (TextBox etc) to Label?
So I can just simply use the same user control, then convert each of the input control to label to display the data... (I just don't really want to use readonly or disable)
Note: I used different dataset to map each of the User Control data....
What I was thinking to do is like to get the input control from Page.Controls:
aInputControl = new Label();
or...
Page.Controls.Remove(aInputControl);
Then somehow add new Label in same position in the page...
But I have no idea how...can't think of anything except add another div to surround each of the control...
I just wonder if it this is possible...
Thanks in advance.
================
Edit: Seems like making new user control is not a good way for me....I will just try to somehow map each original data and new data into a new User control, and write them into page...but anyway, thanks for the idea guys.
You can make a custom user control that contains a TextBox and a Label, and displays one or the other depending on whether or not it has a value.
I would create a user control or a web control to encapsulate that functionality. Add a Property to change the display mode and some logic in the control to determine which control to show.
Here is a sample of code to give you an idea, I can expand on this if you would like.
public class ReadOnlyControl<T> : WebControl where T : Control, ITextControl {
protected T inputControl;
protected Label lblLabel;
public bool IsReadOnly { get; set; }
public string Text { get; set; }
protected override void Render(HtmlTextWriter writer) {
Control control = IsReadOnly ? lblLabel : (Control)inputControl;
((ITextControl)control).Text = Text;
control.RenderControl(writer);
}
}
You may want to rethink your design. I recommend you have another view/page that displays the data summary after submit. Additionally, you will have more control of the formatting this way. I don't want to sound condescending, but it just sounds like you are being a little lazy.
I was wondering about some best practices for data binding in web forms.
For example we have a control:
public partial class MyUserControl : UserControl
{
public override void DataBind()
{
//#1
base.DataBind();
//#2
}
}
If we wanted that control to bind its data automatically we would do something like this:
protected void Page_Load(object sender, EventArgs e)
{
if (!this.IsPostBack)
{
this.DataBind();
}
}
In the first section of code if we do our data binding before the call to base.DataBind() (#1) then that means that, if for example we databind a ListView, we don't have to call ListView.DataBind() because when we call base.DataBind() on our control it recursively calls DataBind on all child controls. Also, we won't have access to any of the properties of the control that were assigned to it using the data binding code blocks <%# %>
If we do our binding on our controls after base.DataBind() (#2) then this means that DataBind is called on these controls twice. Once when base.DataBind() is called, and the second time when we are forced to call control.DataBind().
Does anyone know of some sort of pattern I can follow here that I don't know about?
Am I making any sense here?
What am I doing wrong?
EDIT:
Looking at this page:
http://msdn.microsoft.com/en-us/library/w5e5992d.aspx
Use this method to bind data from a
source to a server control. This
method is commonly used after
retrieving a data set through a
database query. The method is
primarily used by control developers;
most controls perform data binding
automatically.
It appears that best practice is to bind controls data automatically. Databinding is for when we explicitly set a data source.
I've encountered problems previously, when pages become complex and you are relying on user controls binding their own data in the page load event. This has resulted in some long debugging sessions, as you can't be guaranteed exactly when this page load event in the control will fire.
Now, that said, these pages weren't too well designed, and we shouldn't have run into this problem, but I prefer to stick with the explicit and have my page tell the child controls when to do their thing - you may wish to avoid calling base.DataBind and do it explicitly instead - you may also wish to not override the DataBind method in this way and instead call the method on your control by another name.