Clearing all data on tab page when clicking No Button - c#

in my application im submitting a data to the db on a tabControls page(page:tabPage2) and i want when hitting the submit button first saving data to db(im achieving this) the a question will ask anything will be done? if the user hit the no button all fields on tabpage2 will reset. so i wrote a script like below but it is not clearing fields.
if (dr == DialogResult.Yes)
{
for (int i = 0; i < this.tabControl1.Controls.Count; i++)
{
if (this.tabControl1.SelectedTab == tabPage2)
{
if (tabPage2.Controls[i] is TextBox)
{
tabPage2.Controls[i].Text = "";
}
if (tabPage2.Controls[i] is ComboBox)
{
tabPage2.Controls[i].Text = "";
}
if (tabPage2.Controls[i] is PictureBox)
{
tabPage2.Controls[i].Text = "";
}
if (tabPage2.Controls[i] is RadioButton)
{
tabPage2.Controls[i].Text = "";
}
}
}
}

If you control the class for the page layout within the specific tab page you want to clear, it's probably best to create a public or internal method in that class (such as Clear()) which can access each of its member controls and clear them directly. That's the easiest approach, and it should usually apply.
If you instead need it to handle a page with an unknown structure, you might need an approach like:
private void ClearControls(Control parentControl)
{
foreach (Control ctrl in parentControl.Controls)
{
TextBox ctrlText;
ComboBox ctrlCombo;
PictureBox ctrlPicture;
RadioButton ctrlRadio;
// Pay careful attention to the parentheses...
if ((ctrlText = ctrl as TextBox) != null)
{
ctrlText.Text = string.Empty;
}
else if ((ctrlCombo = ctrl as ComboBox) != null)
{
ctrlCombo.SelectedIndex = -1;
}
else if ((ctrlPicture = ctrl as PictureBox) != null)
{
// Logic to clear a PictureBox called ctrlPicture
}
else if ((ctrlRadio = ctrl as RadioBox) != null)
{
// Logic to clear a RadioButton called ctrlRadio
}
else if (ctrl.Controls.Count > 0)
{
ClearControls(ctrl); // Recursively clear contained controls.
}
}
}
With a call to start it off from the original handler:
if (dr == DialogResult.Yes)
ClearControls(this.tabControl1);

You are itering over the collection of TabControl child controls, not actual TabPage's.
Change your code to this instead:
if (dr == DialogResult.Yes && this.tabControl1.SelectedTab == tabPage2)
{
foreach (var ctrl in tabPage2.Controls)
{
if (ctrl is TextBox || ctrl is ComboBox || ctrl is PictureBox || ctrl is RadioButton)
{
ctrl.Text = "";
}
}
}
I should say though than setting the Text property to "" for controls other than TextBox feels rather wrong to me. As you'll find out, this won't work for combos, images and radio buttons.
Also if you have controls nested into panels or the like they won't be cleared. Containers have their own nested collection of controls, which in turn can also be containers, and so on and on.
IMHO it would be far better for you to explicitely reset form controls one by one rather than trying to find them dynamically on your form. This way you'll be free to move your controls around at design time without ever worrying about breaking the resetting logic.
Additional suggestion: you can also attach your controls at design time to an instance of your own IExtenderProvider component which will take care of resetting controls appropriately based on their type.

Related

Check which Controls have Borders c#

I am making a Winforms application. Because I want to redraw some borders I want to loop through the controls and check which controls have a border. Unfortunately I have no idea how to accomplish this.
I know panels and textboxes, etc. have a property BorderStyle but I can not access it while looping through Controls. I use the function from this link : https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.control.controls?view=netframework-4.8 , to loop through the controls.
If you have a panel you can foreach on the panel. I use form load as an event
private void Form1_Load(object sender, EventArgs e)
{
foreach (var item in this.Controls)
{
switch (item.GetType().Name)
{
case "Label":
if (((Label)item).BorderStyle == BorderStyle.None)
{
//Your commands
}
break;
case "TextBox":
if (((TextBox)item).BorderStyle == BorderStyle.None)
{
//Your commands
}
break;
}
}
}
Or you can check them dynamic
I recommend you to use the dynamic way.
in this way, your app wouldn't encounter exceptions or errors
foreach (var item in this.Controls)
{
//Get item from form
dynamic element = item;
//check if there is any property called Borderstyle exists
var res = item.GetType().GetProperties().Where(p => p.Name.Equals("BorderStyle")).FirstOrDefault();
//if it exists and value is not equal None(Control have border)
if (res !=null && !(res.GetValue(item).Equals("None")))
{
res.SetValue(item, BorderStyle.FixedSingle, null);
//your other commands
}
}
You could use a foreach for every type of control you use (TextBox, Label, etc.)
var controlsWithoutBorders = new List<Control>();
// Check textboxes
foreach (var control in controls.OfType<TextBox>())
{
if (control.BorderStyle != BorderStyle.None)
{
controlsWithoutBorders.Add(control);
}
}
//Check labels
foreach (var control in controls.OfType<Label>())
{
if (control.BorderStyle != BorderStyle.None)
{
controlsWithoutBorders.Add(control);
}
}
Alternatively, you could use a single foreach on all the controls, and try to cast the control to each type. The cast will be successful if the control is actually what you want to cast it to, otherwise it will return null (e.g. trying to cast a Control that is a TextBox to a Label will return null)
var controlsWithoutBorders = new List<Control>();
foreach (var control in controls)
{
var controlAsTextBox = control as TextBox;
var controlAsLabel = control as Label;
if (controlAsTextBox != null && controlAsTextBox.BorderStyle != BorderStyle.None)
{
controlsWithBorders.Add(control);
}
if (controlAsLabel != null && controlAsLabel.BorderStyle != BorderStyle.None)
{
controlsWithBorders.Add(control);
}
}
Though this method is not the fastest at run time, your problem could be cleanly solved with the use of C#'s dynamic typing feature. Consider the below snippet of code.
public void DealWithBorder(List<Control> lsControls) {
foreach(var element in lsControls){
dynamic dynamicElement = element;
try{
BorderStyle style = dynamicElement.BorderStyle;
// Handle if property does exist in the control
}
catch{
// Handle if property doesnt exist in the control
}
}
}
In English, it will try to act as if the property exists in the object but if it does not, an exception will thrown. For more info on dynamic typing, click here.

Properly reload form to its initial state after saving data

I know there's many answers closely to this one but I really want an option from someone experienced.
So, after fill in form, user have option to Save data and remain in form, save data and close form or save data and add new record.
For saving, saving and close its pretty simple, but for saving and add new record, I have some problems.
So far, I'm resetting all controls to its original state after save data.
Comboboxes to SelectedIndex = -1;
Textboxes to string.Empty;
Radioboxes to checked = false;
Checkboxes to checked = false;
DatetimeEdit to Values = null;
And this works for resetting controls in a small form.
Is there any other, faster and better way to achieve this goal?
Maybe closing and reopening Form?
All my controls, comboboxes fill and other needs are made in constructor. I do not load anything in Load Event.
In order to do it efficiently and reusebale its possible to do something like this, please see comments:
private void RollBackForm()
{
// put here all the containers the contain the controls, panel,groupbox the form itself etc...
Control[] Containers = { panel1, groupBox1, this };
// iterate trough all containers
foreach (Control container in Containers)
{
// check control type, cast it and set to default
foreach (Control childControl in container.Controls)
{
if (childControl is ComboBox)
{
((ComboBox)childControl).SelectedIndex = -1;
}
else if (childControl is TextBox)
{
((TextBox)childControl).Text = string.Empty;
}
else if (childControl is RadioButton)
{
((RadioButton)childControl).Checked = false;
}
else if (childControl is CheckBox)
{
((CheckBox)childControl).Checked = false;
}
}
}
}

Using findControl to find a child element

I have a Placeholder and I have a dynamically created panel in the placeholder, I also have some dynamically added radio buttons in the panel, now I can usefindControl() to find the radio buttons if they are direct children of the placeholder.
I've literally spent the whole of yesterday trying to find them when they are the child elements of the Panel. How is there a way to do this?
Here's my code below:
PlaceHolder1.Controls.Add(myPanel); //add the panel to the placeholderenter code here
myPanel.Controls.Add(myRadioButton); //add the radiobutton to the panel
You should make method that recursively searches for a control using it's Id. That mean that the method will search for a control inside of (in your case) placeholder. If method finds control, it will return it. If not, it will go search every placeholder's subcontrol, going "deeper". And then, if nothing is found, it will search one more level down, in every placeholder subcontrols' subcontrol etc.)
private Control FindControl(string ctlToFindId, Control parentControl)
{
foreach (Control ctl in parentControl.Controls)
{
if (ctl.Id == ctlToFindId)
return ctl;
}
if (ctl.Controls != null)
{
var c = FindControl(ctlToFindId, ctl);
if (c != null) return c;
}
return null;
}
and then use it like this:
Control ctlToFind = FindControl(myRadioButton.Id, Placeholder1);
if (ctlToFind != null)
{
//your radibutton is found, do your stuff here
}
else
{
// not found :(
}
Finding Controls recursive is an option, but it also has a couple of down-sides.
If you know the ID's of all the controls you can just use FindControl
RadioButtonList myRadioButton = PlaceHolder1.FindControl("Panel1").FindControl("RadioButtonList1") as RadioButtonList;
Label1.Text = myRadioButton.SelectedValue;
But you will need to give your dynamically added controls an ID.
Panel myPanel = new Panel();
myPanel.ID = "Panel1";
RadioButtonList myRadioButton = new RadioButtonList();
myRadioButton.ID = "RadioButtonList1";
PlaceHolder1.Controls.Add(myPanel);
myPanel.Controls.Add(myRadioButton);

Text from textboxes to list

I'm REALLY new to C# and programming overall, so my question might be stupid in your opinion but here it is.
I have created a form which contains 7 textboxes and i want to collect text from these textboxes and add them to a list. I however get an error saying, System.Windows.Forms.TextBox is a 'type' but is used like a 'variable". What should I do?
for (int i = 1; i < 8; i++)
{
if (TextBox[i].Text == "")
{
days.Add("Restday");
}
else
{
days.Add(TextBox[i].Text);
}
}
TextBox is a type. so TextBox[i] is causing you trouble.
You can alway do something like this
foreach(Control ctrl in yourform.Controls)
{
Textbox = ctrl as TextBox;
if(txtBox != null)
{
if (txtBox.Text == "")
{
days.Add("Restday");
}
else
{
days.Add(txtBox.Text);
}
}
}
This work for a basic form. If you have pannel and other container to organize your controls the approch described in Guffa answer might be better. This could also be rewritten as method who accept a collection of Control recursive use to reach all controls.
Put the textbox references in an array so that you can easily loop through them. If your textboxes are named TextBox1 to TextBox7:
TextBox[] boxes = {
TextBox1, TextBox2, TextBox3, TextBox4, TextBox5, TextBox6, TextBox7
};
foreach (TextBox box in boxes) {
if (box.Text == "") {
days.Add("Restday");
} else {
days.Add(box.Text);
}
}
I guess you don't have an array named TextBox that is why the error. You can try following:
List<strig> days = this.Controls.OfType<TextBox>
.Select(r=> string.IsNullOrWhiteSpace(r.Text)
? "Restday" : r.Text)
.ToList();
But the above would give you the textboxes added on the form directly, If these textboxes are inside other control then you can look for recursively
Go into the form editor and select one of your textboxes. Now find the properties window. If it's not visible then click View->Properties Window
One of the properties in there will be the name of the textbox control. Use that to access it's text value like so:
days.Add(txtMyTextboxName.Text);
If you must iterate through the textboxes you can do this:
foreach(var Textbox in this.Controls.OfType<TextBox>())
{
if (Textbox.Text == "")
{
days.Add("Restday");
}
else
{
days.Add(Textbox.Text);
}
}
But bear in mind this is a pretty non-standard approach and not recommended.

how to check if a control of a certain type?

When I use th below code, it works. All the controls are hidden.
foreach (Control ctr in eItem.Controls)
{
ctr.visible = false;
}
However, I want to hide only labels and dropdownlists. That why I'm trying to use the below code without success
foreach (Control ctr in eItem.Controls)
{
if(ctr is Label | ctr is DropDownList)
{
ctr.visible = false;
}
}
EDIT
Here's the whole method
private void HideLabelAndDDLOnPageLoad()
{
foreach (ListViewItem eItem in lsvTSEntry.Items)
{
foreach (Control ctr in eItem.Controls)
{
if (ctr is Label || ctr is DropDownList)
{
ctr.Visible = false;
}
}
}
}
When I remove the if, all the controls get hidden. When I put it back, nothing happens.
Thanks for helping
I think what you are after is || change it to ||...that is the logical or operator.
foreach (Control ctr in eItem.Controls)
{
if(ctr is Label || ctr is DropDownList)
{
ctr.Visible = false;
}
}
| = bitwise operator
|| = logical or operator
Based on your edit
It appears your controls are inside an updatepanel, if that is the case you want to loop for all controls within the updatepanel's content template container.
Here you go:
foreach (Control ctr in UpdatePanel1.ContentTemplateContainer.Controls)
{
// rest of code
if(ctr is Label || ctr is DropDownList)
{
ctr.Visible = false;
}
}
The | is the bitwise or operator.
You are looking for ||, the logical or operator.
if(ctr is Label || ctr is DropDownList)
Without your exact markup we can only guess the solution here.
You must be using another container to wrap your controls inside your ItemTemplate in the ListView, something like a Panel or other containers. When you get the Controls on the list view item you actually get the warping container and not its children(labels, dropdowns etc.)
One solution to this is something like:
foreach (ListViewItem item in lsvTSEntry.Items)
{
item.FindControl("myLabel").Visible = false;
item.FindControl("myDropdownList").Visible = false;
}
Basically you try to find the controls by id and hide them. Notice there is no error checking there so you could get a NullReferenceException if FindControl returns null.
In case you have nested containers in your ItemTemplate and you want to hide all the labels and dropdowns regardless of where they are you can implement your own recursive FindControl that will look like:
private Control FindControlRecursive(Control rootControl, string controlId)
{
if (rootControl.ID == controlId)
{
return rootControl;
}
foreach (Control controlToSearch in rootControl.Controls)
{
Control controlToReturn = FindControlRecursive(controlToSearch, controlId);
if (controlToReturn != null)
{
return controlToReturn;
}
}
return null;
}
Not the most elegant but.... You can change this to take an array of Id's of course for speed purposes.
Based on this of course you can implement the search by control type which instead of taking a controlId as a parameter will take the types of controls to find.

Categories