I have stumbled across a problem with my asp.net form.
Within my form the end user chooses a number of textboxes to be dynamically created, this all works fine with the following code:
protected void txtAmountSubmit_Click(object sender, EventArgs e)
{
int amountOfTasks;
int.TryParse(txtAmountOfTasks.Text, out amountOfTasks);
for (int i = 0; i < amountOfTasks; i++)
{
TextBox txtAddItem = new TextBox();
txtAddItem.ID = "txtAddItem" + i;
txtAddItem.TextMode = TextBoxMode.MultiLine;
questionNine.Controls.Add(txtAddItem);
txtList.Add(txtAddItem.ID);
}
}
However this has also caused a small problem for me, later on in my form on the submit button click, I send the results to the specified person it needs to go to (using smtp email). Again this part is fine, until I am trying to retrieve the text from these dynamically created textboxes.
What I have tried
I have tried using this msdn access server controls ID method however this was not working.
I tried to add these new textboxes to a list, however I was unsure on how to update these textboxes when they have text in them. Therefore my results were returning null because of this.
I have also looked at other questions on SO such as this however they are usually for WPF or winforms, rather than my problem with asp.net (this usually isn't an issue, but I don't need to get the text from every textbox control in my page, just the ones that were dynamically created).
I have also tried changing how I call the code that I hoped would have worked:
string textboxesText = string.Join("\n", txtList.Select(x => x).ToArray());
and then in my concatenated string (email body) I would call:
textboxesText
The problem
As they are dynamically created I am finding it difficult to call them by their id for example: txtExampleID.Text, also as I have to increment the ID's by one each time (so they don't override each other) it has made things a little bit more difficult for me.
I am not asking for a code solution, I would prefer pointers in the right direction as I am still learning.
So to sum it all up: I need to get the text from my dynamically created textboxes to add it to my email body.
The issue is these text boxes need recreated in the Load event of the page, every single time, so that both events and values can be hooked back up and retrieved.
I think the most straight forward approach, in your case, would be to extend idea #1 that you had already tried. Build a List of these controls with enough information to recreate them in Load, but you need to store that List in either ViewState or Session.
ViewState["DynamicControls"] = list;
or
Session["DynamicControls"] = list;
I would use ViewState if you can because it gets destroyed when the user leaves the page.
Related
I'm currently working on a report using Telerik Reporting (release Q1 2013), and I'm attempting to add a textbox at runtime to a header (and eventually the detail section as well), but the issue is the textbox that gets added does not show up. I'm not sure why it's not displaying, but there are no errors that occur after it is added. Right now I'm trying to add it during the itemdatabinding event. My code is below:
public partial class _WellPlateReport : Telerik.Reporting.Report
{
public _WellPlateReport(Dictionary<string, object> ReportParameters)
{
//
// Required for telerik Reporting designer support
//
InitializeComponent();
tbGenotype.Visible = false;
//
// TODO: Add any constructor code after InitializeComponent call
//
}
private void labelsGroupHeaderSection_ItemDataBinding(object sender, EventArgs e)
{
string temp = "";
Telerik.Reporting.Processing.GroupSection headerGroup = (Telerik.Reporting.Processing.GroupSection)sender;
Telerik.Reporting.TextBox tb = new Telerik.Reporting.TextBox();
tb.Left = new Telerik.Reporting.Drawing.Unit(0.5, UnitType.Inch) + tbGenotype.Left + tbGenotype.Width;
//tb.Width = new Telerik.Reporting.Drawing.Unit(3.0, UnitType.Inch);
tb.Size = tbSex.Size;
tb.Name = "TestLabel1";
tb.Value = "Test Label";
tb.Location = new Telerik.Reporting.Drawing.PointU(tbGenotype.Left + tbGenotype.Width + new Telerik.Reporting.Drawing.Unit(0.5, UnitType.Inch), Telerik.Reporting.Drawing.Unit.Inch(0D));
//this.labelsGroupHeaderSection.Items.Add(tb);
//this.Items.AddRange(new Telerik.Reporting.ReportItemBase[] { tb });
this.labelsGroupHeaderSection.Items.AddRange(new Telerik.Reporting.ReportItemBase[] { tb });
}
}
The tbGenotype is another textbox that the new textbox will be added next to at runtime, so i'm using the positioning of that to place the dynamic textboxes. There is an unknown number of additional columns that will need to be added, but I'm not sure why this isn't working. My searches showed others adding controls in a similar way.
Update: Also note, that the textbox tbGenotype was added in the designer in visual studio. Trying to set the visible property on that works, but adding the textbox to the header does not.
Try to look at this documentation. The only difference that I noticed was that they are adding the textbox to a panel. Then they are adding panel to the report. Check if tbGenotype is added in a panel or not but I think that every element you put in a report has to be in same panel first.
I have the same problem, but I notice when I refresh the report with the refresh button inside the report viewer (in my windows application; should be the same for the web version), the dynamically added controls show up. When I refresh a second time, an additional (second) set of controls shows up.
My observation is this: on initial run, the controls are added, but not visible (regardless of the visible property value being true). On first refresh (second server/application run), a second set of controls is added, not visible, and the first set is now visible. On the second refresh / third run, a third set of not visible controls is added, and the first 2 sets of controls are shown.
First, I need to clear my parent panel(s) of all dynamically added items before adding again. But, to the point of the question, calling ReportViewerInstance.RefreshReport() should cause the dynamically added controls to become visible before the initial rendering of the report. I am about to try this scenario. I am not certain yet how I am going to call the instance of the report viewer, but at minimum, I should be able to pass a reference to the instance as a report parameter, or similar.
RefreshReport() call found in this Telerik help post:
I will update with my results after trying the above.
UPDATE: RefreshReport did NOT work for me - it cancelled the processing and resulted in no report. However, I did solve my issue. And, it should solve the OP's issue as well.
Eric's code shows trying to create and show the dynamically added controls in an ItemDataBinding event. I was doing the same, and also tried ItemDataBound. Both of these events occur when processing is in action, and a help topic regarding a dynamically added table control tipped me off. The Telerik expert recommended not altering the report items during processing to avoid unpredictable behavior. Following that, I moved my code to create controls into a method (not an event) and call it from my Report.NeedDataSource event, after instantiating all needed data objects, and before setting the report datasource as one of my object collections. This works great!
I hope this helps someone else!
I have the following code in an aspx.cs file:
protected void Page_Load(object sender, EventArgs e)
{
epdc = new edu_portalDataContext();
IQueryable<Assignment> _assignmentsList =
from assignment in epdc.Assignments
select assignment;
assignmentsList = _assignmentsList.GetEnumerator();
assignmentsList.MoveNext();
ListOfAssignments.DataSource = epdc.Assignments;
ListOfAssignments.DataBind();
}
Notes, to make it possible for you to understand the code:
Assignments is the name of the database table from which I'm pulling data.
ListOfAssignments is the ID of a Repeater control.
assignmentsList is used in the ListOfAssignments_ItemDataBound method.
Anyway, this is straightforward enough -- instantiate a data context, send it a basic query, get an enumerator, bind some data to a repeater. This part works. The next part is what confuses me.
Later on in the code, I have a click event tied to a Button control. What I want to happen is, the user enters some data in some fields, the user clicks on the button, the program makes a new record with that data, the program sends it off to the database, the database stores the new data, the Repeater (ListOfAssignments) updates with the new database data, and the user sees the new data on the page.
Here's the code in the click event:
Assignment newAssignment = new Assignment
{
//data is entered here
//...
};
epdc.Assignments.InsertOnSubmit(newAssignment);
epdc.SubmitChanges();
But here's what actually happens: when the user clicks the button, everything goes as expected, except the repeater doesn't update with the new data. I did a little debugging, and here's what I found:
assignmentsList doesn't update with the new database data. I looked around in Visual Studio's variable inspector, and the LINQ query doesn't pull in any of the new data. It's as if the user never entered anything at all. Until they refresh the page, that is: when they refresh, the Repeater updates and shows the new data.
Why doesn't the LINQ query give me fresh data on a postback?
Your click event is happening AFTER Page_Load. So the repeater is rebound before the new data is added. Do your databinding in PreRender.
For an outside of the box idea on a particular site I'm building, I would like to use a drop down list control, which has two inputs: Sponsor1 and Sponsor2. My goal is that when a visitor chooses one of the options, they will go a page for that particular sponsor, and enter a pre-defined code via a textbox w/ a "Next" button, which will take them to yet another page to enter more info.
I'm sort of dividing the site up to have branches, as the sponsors will have visitors (i.e., customers) and the sponsors can keep track of these visitors via the input that will go to a database yet to be made.
As I'm creating this in Asp.Net/C#, I cannot find any examples of this being done, outside an old reference being done with JavaScript - yet the end concept is not the same:
Creating a drop-down list that links to other pages
So is this possible to code something in C# within the code-behind to make this behave as I wish, or must I scrap this idea and just do it another way? Thanks to all in advance!!
Have you tried calling an event when the user selects something on the drop-down list?
Edit: Added more context to where everything goes.
protected override void OnInit(EventArgs)
{
dropDownList.selectedIndexChanged += new EventHandler(ddlIndexChanged);
base.OnInit(ea);
}
//Your Page_Load Here
private void ddlIndexChanged(object sender, EventArgs ea)
{
//This is called when the index is changed, you could redirect here
}
What is the best way to create and read multiple textboxes in a windows form? In my application, I have a windows form where customer can enter multiple addresses, email addresses
Right now I have a form like this,
TextBoxAddress1 TextBoxEmail1
TextBoxAddress2 TextBoxEmail2
.....
.....
.....
TextBoxAddressN TextBoxEmailN
For this I dragged and dropped multiple controls on a form and named each one of them.
If I use this method I had to write lengthy code to see if first row (TextBoxAddress1 TextBoxEmail1) is filled for validation and even for reading I had to write many lines of code.
Is there a better to way achieve this?
You can use the following code to add a TextBox dynamically to your form:
private int m_CurrTexboxYPos = 10;
private List<TextBox> m_TextBoxList = new List<TextBox>();
private void CreateCheckBox()
{
m_CurrTexboxYPos += 25;
TextBox textbox = new TextBox();
textbox.Location = new System.Drawing.Point(0, m_CurrTexboxYPos);
textbox.Size = new System.Drawing.Size(100,20);
Controls.Add(textbox);
m_TextBoxList.Add(textbox);
}
I would have a listbox/listview with your emails and Add/Edit/Delete buttons which show a popup form - the logic for validating emails, etc. would then be in the one place and your list can grow without you ever needing to add controls to the form.
You could dynamically create textboxes - but you end up writing code to make sure they layout nicely on the form, etc. - having some type of list is easier IMO and also lends itself to binding (e.g. to an email object)
Dynamically adding controls is pretty simple, provided you can use DockStyle and an exclusive container for them (e.g. a Panel). If you can't use DockStyle, then you need to write logic to determine Location and Size (which isn't fun).
On a simple form, I have two buttons and a panel, Button1 adds a new TextBox to Panel1, Button2 iterates through the controls in Panel1 and then checks that they are the correct type or throws an exception. This is where you you would put validation or reading logic. Panel1 needs to have AutoScroll = true; otherwise you will run controls off of the viewable screen.
This concept can be switched for anything that inherits from UserControl (all .Net native controls or your own custom controls).
private void button1_Click(object sender, EventArgs e)
{
TextBox NewEmailBox = new TextBox();
NewEmailBox.Name = "NewEmailBox" + this.panel1.Controls.Count;
NewEmailBox.Dock = DockStyle.Top;
this.panel1.Controls.Add(NewEmailBox);
}
private void button2_Click(object sender, EventArgs e)
{
foreach (Control item in this.panel1.Controls)
{
if (item is TextBox)
{
//Do your reading/validating here.
}
else
{
throw new InvalidCastException(string.Format("{0} was in Panel1 and is of type {1} not TextBox!", item.Name, item.GetType()));
}
}
}
Write a user control for each of the groupings you need. at least one One for address, one for email etc. then all of your validation, calls to your database access is contained in a single location
That is just good design. this way if you have multiple tabs for things like Home Information, Work Information, Emergency Contact Information, you can just place them on the form. This is pretty common for a user profile.
Then a listview for each grouping on a user profile page or whatever, that has edit/delete/add then popup a dialog with the appropriate user control in it.
Most simply, ListBox adove TextBox with Button.
Also you can use DataGridView, BuiltIn functionality for Add\Edit\Delete.
Here using DataGridView (ShowHeader set to false, EditMode to On Enter, with one Column with AutoSizeMode in Fill property)
The less of repeatable code you have, the better programmer you are.
Whenever you see a pattern (something what is repeatable), you could and you should try to optimize it. Unless it's something too small to worry.
In your case, determine first what is the basic of repeatable thing. Do you always have to enter address and email address? Then combine them into a control, which can carry out validation. Do you have to use this control often (or repeat N times)? Then maybe it make sense to switch to a list instead (ListBox, ListView or DataGridView).
Are you too lazy to bother configuring things? Then just optimize something what is obviously going to repeat: put validation into common method and call it from each TextBox event. Or make own TextBox with method build-in. Or do validation at once in the Ok button event by using loop.. or not by using loop.
To find best method you have to first decide best for who. Because customer want something shiny,easy to use, animated, with cats and boobs.. ok, without cats and boobs. The point is: how much work are you willing to put to have it best for the customer.
If I would have to enter table data (or data which form table), I'd go with DataGridView so it would looks like this.. or better:
I have a web form where I register a new employee. There're 3 parts in the form: Personal info, Address info, Special Status. But there's only one button for the whole form. When I submit the form all the information is updated to the database. So three Update statements are executed against the database. The methods are UpdatePersonalInfo, UpdateAddressInfo and UpdateSpStatus. Is there a way to check if there's been a change in any field in the certain part and run update method only if it's true. So something like this:
if (There's been any change to the personal data of the employee)
{
UpdatePersonalInfo;
}
if (There's been any change to the address information of the employee)
{
UpdateAddressInfo;
}
Sure I know, I can save all the previous values in a session object in PageLoad and then compare them one by one before running the method. But I thought maybe there's a magic way of doing this more easily.
Not sure that this is a better solution than any of the alternatives you already mentioned, but you could create a default handler to attach to the TextChanged, SelectedIndexChanged, etc events of your controls to keep track of which ones have changed.
List ChangedControls = new List(Of, String);
private void ChangedValue(object sender, System.EventArgs e) {
WebControl cntrl = (WebControl) sender;
ChangedControls.Add(cntrl.ID);
}
Then on your button click scour the ChangedControls list for the relevant controls.