Clearing MOST labels on form, NOT all - c#

I need to clear 32 labels on my windows form application, there are other labels present but I do NOT want to clear these. Is there a more efficient and less coded way to do this? My code for this at the moment is as follows using a method: (snippet)
private void ClearFields()
{
label50.Text = string.Empty;
label51.Text = string.Empty;
label52.Text = string.Empty;
label53.Text = string.Empty;
label54.Text = string.Empty;
label55.Text = string.Empty;
// Down to label82
}
I have researched but it's always clearing ALL labels/textboxes.

You could add an object to the Tag of the Label you want to clear.
Label label50 = new Label();
bool deleteMe = true;
label50.Tag = deleteMe;
Then just iterate over your labels and clear all where the Tag is true:
foreach(Label lbl in myLabels)
{
if(lbl.Tag != null && lbl.Tag is bool && (bool)lbl.Tag == true)
{
lbl.Text = String.Empty;
}
}

Try following line:
foreach (Label _label in this.Controls.OfType<Label>().Where(a => a.Name != "Lable32").Select(a => a).ToArray())
_label.Text = string.Empty;
Add non removal lable in where condition if there are many. Here except lable32 all lable text will set to empty.

I would recomend you to place all the labels that need to be cleared in some kind of cointainer. That way you can do something of the sort:
foreach (var child in container.Children)
{
if (child is Label)
{
((Label)child).Text=String.Empty;
}
}
I am not very familiar with WinForms, but I think there are containers there.

Set the Tag property of the labels you do not want cleared to the string "DoNotClear" (using the Property Window or code) then use the following LINQ code:
foreach (var label in Controls.OfType<Label>().Where(l => l.Tag != "DoNotClear"))
label.Text = string.Empty;

Solution : you can use Controls.Find() method to find the controls from id label50 to label82 and assign String.Empty for each identified Label.
Try This:
private void button1_Click(object sender, EventArgs e)
{
for(int i=50;i<83;i++)
{
this.Controls.Find("label" + i,true)[0].Text = String.Empty;
}
}

If all your labels have names like label + id
var labelsToClear = from l in Controls.OfType<Label>()
let id = Int32.Parse(l.Name.Replace("label", ""))
where id >= 50 && id <= 82
select l;
foreach(var label in labelsToClear)
label.Text = String.Empty;
If labels can have different names, then you can filter out labels which match label + id pattern:
Controls.OfType<Label>().Where(l => Regex.IsMatch(l.Name, #"^(?:label)\d+$"))

Related

TableLayoutPanel update lag

I have a WinForms app which is updating a TableLayoutPanel from a BackgroundWorker. Depending whether a device input is On (1) or off (0) the colour and some text is changed accordingly.
try
{
//Define a new TLP to hold the search tablelayoutpanel.
//search for the iterated card number.
//get the status label using GetControl from Position.
TableLayoutPanel TLP = new TableLayoutPanel();
string IO_Card_Name = "ED527_" + i.ToString();
TLP = TLP_IO_Info.Controls.Find(IO_Card_Name, true).FirstOrDefault() as TableLayoutPanel;
try { lbl = TLP.GetControlFromPosition(4, 0) as Label; } catch { lbl = null; };
//if card is found (because input is active, colour the TLP (card) according to its state.
if (TLP != null && lbl != null && INPUTS[i - 1] == 1)
{
TLP.BackColor = Color.Green;
foreach (Label l in TLP.Controls)
{
l.BackColor = Color.Green;
}
lbl.Invoke((MethodInvoker)delegate { lbl.Text = "ON"; });
}
else if (TLP != null && lbl != null && INPUTS[i - 1] == 0)
{
TLP.BackColor = Color.White;
foreach (Label l in TLP.Controls)
{
l.BackColor = Color.White;
}
lbl.Invoke((MethodInvoker)delegate { lbl.Text = "OFF"; });
}
}
catch (Exception exception)
{
MessageBox.Show(exception.Message);
};
TLP holds 5 labels in it. The update shows some noticeable lag when the line updates. Is there a way I can carry out something akin to SuspendLayout() / ResumeLayout on the main UI thread?
****EDIT to show the before and after - the IOLabel column updates slightly before the Status column.
Sounds you have a nested design. Each row is 5 Labels are hosted by different TableLayoutPanels and the TLP_IO_Info which is a TableLayoutPanel hosts the other TableLayoutPanels. In the DoWork event of the BackgroundWorker you have a for..loop to change the Backcolor of the inner controls according to the current state of the devices which you read it from the INPUT int array. Please correct me.
I'd like to suggest this:
foreach (var tlp in TLP_IO_Info.Controls.OfType<TableLayoutPanel>()
.Where(x => x.Name.StartsWith("ED527_")))
{
if (tlp.GetControlFromPosition(4, 0) is Label lbl)
{
var state = // get the state of the current device from INPUT array
var stateColor = state == 1 ? Color.Green : Color.White;
var stateText = state == 1 ? "ON" : "OFF";
this.Invoke(new Action(() =>
{
tlp.BackColor = stateColor;
tlp.Controls.OfType<Label>().ToList().ForEach(l => l.BackColor = stateColor);
lbl.Text = stateText;
}));
}
}
Or this to eliminate the redundant code:
var stateColors = new[] { Color.White, Color.Green };
var stateTexts = new[] { "OFF", "ON" };
foreach (var tlp in TLP_IO_Info.Controls.OfType<TableLayoutPanel>()
.Where(x => x.Name.StartsWith("ED527_")))
{
if (tlp.GetControlFromPosition(4, 0) is Label lbl)
{
var state = // get the state of the current device from INPUT array
this.Invoke(new Action(() =>
{
tlp.BackColor = stateColors[state];
tlp.Controls.OfType<Label>().ToList()
.ForEach(l => l.BackColor = stateColors[state]);
lbl.Text = stateTexts[state];
}));
}
}
Note that, I've removed the expensive try..catch blocks since this code won't throw any exceptions.
As for the INPUT array, I suggest that you replace it with a Dictionary<string, int> to store the current state of each device since (according to the link you've provided) each device has a unique IOLineNumber so you can easily set/get the current state of each one.
⍰ Maybe there is already something like this in the library?

How to set a variable in a labelname

in my project i have 8 dynamic Textboxes and 8 dynamic Labels, which were created in c#.
Now i need to read the text in it and insert it in a db.
My current script looks like
Label labelname1 = this.Controls.Find("label1", false).FirstOrDefault() as Label;
Label labelname2 = this.Controls.Find("label2", false).FirstOrDefault() as Label;
Label labelname3 = this.Controls.Find("label3", false).FirstOrDefault() as Label;
.....
Is it possible, to create a while loop with a variable like:
int i = 1;
while (a < 9)
{
label Labelname+i = this.Controls.Find("label+i" + a, false).FirstOrDefault() as Label;
i++;
}
When I take the "labelname+i" it's not possible, because it isn't a string.
Thank you
Extract method then
private T FindControl<T>(string name) where T : Control {
return this
.Controls
.Find(name, false)
.OfType<T>()
.FirstOrDefault();
}
and use it in a loop (it seems you want for one):
for (int i = 1; i < 9; ++i) {
Label myLabel = FindControl<Label>($"label{i}");
if (myLabel != null) {
//TODO: Put relevant code here
}
}
Same loop if you want to enumerate TextBoxes:
// textBox1..textBox8
for (int i = 1; i < 9; ++i) {
TextBox myTextBox = FindControl<TextBox>($"textBox{i}");
if (myTextBox != null) {
//TODO: Put relevant code here
}
}
You can create a List of Labels and try like:
List<Label> labels = new List<Labels>();
for (int i=1;i<9;i++)
{
Label lbl = this.Controls.Find("label"+i.ToString(), false).FirstOrDefault() as Label;
labels.Add(lbl);
}
And if you want to access i Label you simply do:
labels[i] ...

How to hide all text boxes if they are empty

I'm just wondering really.
I have series of if statements that check
if textboxes are empty (or have results strings) after i pass SQL
results to then
.
if (IncidentData.Tables[0].Rows[0]["Property Category"].ToString()
== "RoadVehicle")
{
lbl_alarmOperated.Visible = false; tb_alarmOperated.Visible = false;
}
else
{
lbl_alarmOperated.Visible = true;
tb_alarmOperated.Visible = true;
}
I have been looking into controls and seeing if i can do a check on all textboxes and hide them if they are empty (instead of writing loads of if statements)
i have this at the moment:
public void ChecknHide()
{
HideTextBoxes(this);
}
protected void HideTextBoxes(Control ctrl)
{
foreach (var c in ctrl.Controls)
{
if (c is TextBox) ((TextBox)c).Text = String.Empty;
{
((TextBox)c).Visible = false;
}
}
}
Its mostly put together from reading posts on here. But I've ran into an issue. When i compile and go to view the page i get this:
Unable to cast object of type 'ASP.masterpage_master' to type
'System.Web.UI.WebControls.TextBox'.
Any ideas whats going wrong?
The statement after the if isn't part of the condition. This causes all controls to be casted to a TextBox. You should be able to fix it like so:
protected void HideTextBoxes(Control ctrl)
{
foreach (var c in ctrl.Controls)
{
if (c is TextBox && ((TextBox)c).Text == String.Empty)
{
((TextBox)c).Visible = false;
}
}
}
Weird code line:
if (c is TextBox) ((TextBox)c).Text = String.Empty;
Try something like:
protected void HideTextBoxes(Control ctrl)
{
//Iterate over controlls
foreach (var c in ctrl.Controls)
{
//Check for Textbox controls with the .Text property equal to Null or Empty.
if (c is TextBox && string.IsNullOrEmpty(((TextBox)c).Text))
{
//Set visibility of Textbox control to invisible.
((TextBox)c).Visible = false;
}
}
}
You're checking if c is a TextBox, but then trying to cast c as a TextBox and set it to String.Empty in the same line, regardless of whether it actually is a TextBox.
if (c is TextBox) ((TextBox)c).Text = String.Empty;

How to create textbox dynamically in C# asp.net?

I would need some advice or ideas on the problem I'm facing.
I would like to to create a textbox dynamically from an input string like example '11211'.
When it read the first character based on the string above, in this case '1', a textbox with background color yellow would be created.
The loop would continue creating textboxes horizontally till finished reading all the characters in string above.
Snippet of the code is as below :-
foreach (XmlNode xn in list1)
{
string name = xn["BinCode"].InnerText;
disGood.Text = name;
string input = name;
disOccupied.Text = input.Length.ToString();
char[] b = name.ToCharArray();
foreach (char c in b)
{
TextBox[] theTextBoxes = new TextBox[1];
for (int i = 0; i < theTextBoxes.Length; i++)
{
theTextBoxes[i] = new TextBox();
if (c.ToString() == "1")
{
theTextBoxes[i].BackColor = Color.Yellow;
}
}
disGood.Text = c.ToString();
}
}
Some sample or ideas would be high recommended.
Thank you.
I see a lot of redundancies. For example: your array of textboxes is useless, since you always create one textbox during each iteration. The assignment to the extra variable input and b are extra, but unneeded operations. Try this:
foreach (XmlNode xn in list1)
{
string name = xn["BinCode"].InnerText;
disGood.Text = name;
disOccupied.Text = name.Length.ToString();
foreach (char c in name) // You can iterate through a string.
{
TextBox theTextBox = new TextBox();
if (c == '1') // Compare characters.
{
theTextBox.BackColor = Color.Yellow;
}
Controls.Add(theTextBox); // Add the textbox to the controls collection of this parent control.
disGood.Text = c.ToString(); // This will only show the last charachter. Is this as needed?
}
}
To dynamically create and display textbox's horizontally use the below code:
TextBox t = new TextBox()
{
//To display textbox horizontally use the TableLayoutPanel object
TableLayoutPanel(TextBox, Column, Row);
//add any properties specs,
//more property specs,
};

A Better way? Finding ASP.NET controls, finding their id

I have a method that finds all the controls, iterates through them, determines if they are a textbox,drop down list, etc.. retrieves their ID name, and depending on the ID name it will set a boolean statement (thus I would know if that section of the form is complete, and will email to a certain group of people) unfortunetly this is done with too many if statements and was wondering if I could get some help making this more manageable
protected void getEmailGroup()
{
Control[] allControls = FlattenHierachy(Page);
foreach (Control control in allControls)
{
if (control.ID != null)
{
if (control is TextBox)
{
TextBox txt = control as TextBox;
if (txt.Text != "")
{
if (control.ID.StartsWith("GenInfo_"))
{
GenInfo = true;
}
if (control.ID.StartsWith("EmpInfo_"))
{
EmpInfo = true;
}
}
}
if (control is DropDownList)
{
DropDownList lb = control as DropDownList;
if (lb.SelectedIndex != -1)
{
if (control.ID.StartsWith("GenInfo_"))
{
GenInfo = true;
}
if (control.ID.StartsWith("EmpInfo_"))
{
EmpInfo = true;
}
}
}
}
}
}
Why not just use the Control.FindControl(string) method?
private void Button1_Click(object sender, EventArgs MyEventArgs)
{
// Find control on page.
Control myControl1 = FindControl("TextBox2");
if(myControl1!=null)
{
// Get control's parent.
Control myControl2 = myControl1.Parent;
Response.Write("Parent of the text box is : " + myControl2.ID);
}
else
{
Response.Write("Control not found");
}
}
from: https://learn.microsoft.com/en-us/dotnet/api/system.web.ui.control.findcontrol
It is hard to understand the logic behind your code, but I'm sure it can be written easier. For example you can do something like this:
DropDownBox box = FlattenHierachy(Page)
.Where(c => c is DropDownList)
.Cast<DropDownList>()
.Where(d => d.SelectedIndex != -1)
.FirstOrDefault();
if (box != null)
{
if (box.ID.StartsWith("GenInfo_"))
{
GenInfo = true;
}
if (box.ID.StartsWith("EmpInfo_"))
{
EmpInfo = true;
}
}
Obviously you can make this generic if you extract the lambda expression from the seconde Where call. So you could reuse it for different types. That's the solution which is as close to your code as possible, but I guess it would be a better idea to use a recursive method traversing the page and giving that method your predicates as lambda expressions.
Cleaned up you code a little to only include each check once.
protected void getEmailGroup()
{
Control[] allControls = FlattenHierachy(Page);
foreach (Control control in allControls)
{
if (control.ID != null &&
((control is TextBox && ((TextBox)control).Text = "" )
|| (control is DropDownList && ((DropDownList)control).SelectedIndex != -1 ))
{
if (control.ID.StartsWith("GenInfo_"))
GenInfo = true;
if (control.ID.StartsWith("EmpInfo_"))
EmpInfo = true;
}
}
}
}
Instead of using the Lambda expression I have created a method that handles the control for me, and depending on the name of the control, it sets that section to be true
public bool setGroup(Control ctrl)
{
isAControl = false;
//set a section to true, so it will pull the html
if (ctrl.ID.StartsWith("GenInfo_"))
{
GenInfo = true;
lstControls.Add(ctrl.ID.Replace("GenInfo_", ""));
isAControl = true;
return isAControl;
}
here is a small snippet of my code I only want to check for certain controls(to speed things up) and I go through each control as each control has a different way to get the value (textbox would use .text where dropdownlist would use .selectedValue)
if(control is TextBox || control is DropDownList || control is RadioButton || control is RadioButtonList
|| control is CheckBox || control is CheckBoxList)
{
if (control is TextBox)
{
TextBox txt = control as TextBox;
if (txt.Text != "" && txt.Text != "YYYY/MM/DD")
{
setGroup(control);
if (isAControl)
{
string controlNoGroup = lstControls.Last();
strHtml = strHtml.Replace("#" + (controlNoGroup.ToString()) + "#", txt.Text);
}
}
}

Categories

Resources