I'm trying to Search through a series of contacts. (saved in an xml file, and then recovered to the variable myContacts) the code for searching is fine, it gets the right results, my problem is Showing the contact in the text boxes.
This is my code for showing the results in the text boxes:
private void showContact(int index)
{
txtNameResult.Text = myContacts[index].getName();
txtFNameResult.Text = myContacts[index].getFName();
txtNumberResult1.Text = myContacts[index].getSingleNumber(0);
int position = 30;
for (int i = 1; i < myContacts[index].getNumCount(); i++)
{
TextBox formtxtBox = txtNumberResult1;
TextBox txtMyNum = new TextBox();
gbResult.Controls.Add(txtMyNum);
txtMyNum.Size = formtxtBox.Size;
txtMyNum.Location = new Point(formtxtBox.Location.X, formtxtBox.Location.Y + position);
position += 30;
txtMyNum.Text = myContacts[index].getSingleNumber(i);
txtMyNum.ReadOnly = true;
txtMyNum.Name = "txtNumberResult" + (i + 1).ToString();
txtMyNum.TabIndex = i + 2;
if (this.Height < 414)
{
gbResult.Height += 30;
this.Height += 30;
}
}//end of for
}//end of show contact
and this is my form:
![search
Form][1]
each contact can have up to 5 numbers and with each extra number a text box is added under the txtNumberResult1 and the groupbox and form height are extended.
the problem is that when I search for a contact with 5 numbers it shows it correctly but if I search for another contact AFTER that, the extra textboxes don't delete.
this is rather odd, but after an hour of debugging I finally found out that the problem is in my clearResults() code the gbResult.Controls.count (gbResult is the groupbox) is 8 (it should be 11 now)
this is my clearResults() code(the code that executes at the beginning of Save button click event, it resets everything):
private void clearResults()
{
gbResult.Focus();
txtNameResult.Text = "";
txtFNameResult.Text = "";
txtNumberResult1.Text = "";
foreach (Control txtBox in gbResult.Controls)
{
if (txtBox.GetType() == typeof(TextBox))
{
if (txtBox.Name != "txtNumberResult1" && txtBox.Name != "txtNameResult" && txtBox.Name != "txtFNameResult")
{
//remove the controls
txtBox.Text = "";
gbResult.Controls.Remove(txtBox);
txtBox.Dispose();
}//end of if
}//end of if
}//end of foreach
//shrink the form
while (this.Height > 294 && gbResult.Height > 129)
{
this.Height -= 30;
gbResult.Height -= 30;
}
}//end of clear results
thank you in advance and sorry if it seems a bit confusing!
PS: I can't post images as I don't have the required rep :|
EDIT:
This is the correct clearResults() method:
private void clearResults()
{
gbResult.Focus();
txtNameResult.Text = "";
txtFNameResult.Text = "";
txtNumberResult1.Text = "";
//foreach (Control txtBox in gbResult.Controls)
for (int i = 15; i > -1; i--)
{
try
{
var txtBox = gbResult.Controls[i];
if (txtBox.GetType() == typeof(TextBox))
{
if (txtBox.Name != "txtNumberResult1" && txtBox.Name != "txtNameResult" && txtBox.Name != "txtFNameResult")
{
//remove the controls
txtBox.Text = "";
gbResult.Controls.Remove(txtBox);
txtBox.Dispose();
}//end of if
}//end of if
}//end of try
catch (Exception)
{
continue;
}
}//end of for
//shrink the form
while (this.Height > 294 && gbResult.Height > 129)
{
this.Height -= 30;
gbResult.Height -= 30;
}
}//end of clear results
For those who have the same problem :)
In your clearResult() method try removing the controls in reverse order:
for (int i = 20; i > -1; i--)
Related
I just started with the programming language C# a week ago and used the program Visual Studio with win Forms. I've had a problem for a few days.
I want to connect a ProgressBar to different TextBoxes. So that with each filled textBox the ProgressBar increases. When the text is removed, the progressBar should go down again.
So far I've only managed to get the progressBar to increase in general or that the progress bar increases with each letter in a textBox.
Textboxes are Vorname,Nachname,PLZ,Wohnort,Hausnummer,Straße
ProgressBar is Fortschrittsanzeige
private void button1_Click(object sender, EventArgs e)
{
Fortschrittsanzeige.Dock = DockStyle.Bottom;
Fortschrittsanzeige.Maximum = 60;
Fortschrittsanzeige.Minimum = 0;
Fortschrittsanzeige.Style = ProgressBarStyle.Continuous;
if (
Vorname.Text.Length <= 0 ||
Nachname.Text.Length <= 0 ||
PLZ.Text.Length < 4 ||
Wohnort.Text.Length <= 0 ||
Hausnummer.Text.Length <= 0 ||
Straße.Text.Length <= 0
)
{
textBox7.Text = ("Bitte überprüfe deine Eingabe");
}
else
{
Sendebutton.Text = "Gesendet";
textBox7.Text = "Vielen Dank" + Vorname.Text + " " + Nachname.Text + ", wir
haben deine Daten erhalten.";
}
if (Vorname.Text.Length <= 0)
{
Vorname.BackColor = Color.IndianRed;
}
else
{
Vorname.BackColor = Color.White;
Fortschrittsanzeige.Value += 10;
}
if (Nachname.Text.Length <= 0)
{
Nachname.BackColor = Color.IndianRed;
}
else
{
Nachname.BackColor = Color.White;
Fortschrittsanzeige.Step += 10;
}
if (PLZ.Text.Length < 4)
{
PLZ.BackColor = Color.IndianRed;
}
else
{
PLZ.BackColor = Color.White;
Fortschrittsanzeige.Step += 10;
}
if (Wohnort.Text.Length <= 0)
{
Wohnort.BackColor = Color.IndianRed;
}
else
{
Wohnort.BackColor = Color.White;
Fortschrittsanzeige.Step += 10;
}
if (Hausnummer.Text.Length <= 0)
{
Hausnummer.BackColor = Color.IndianRed;
}
else
{
Hausnummer.BackColor = Color.White;
Fortschrittsanzeige.Step += 10;
}
if (Straße.Text.Length <= 0)
{
Straße.BackColor = Color.IndianRed;
}
else
{
Straße.BackColor = Color.White;
Fortschrittsanzeige.Step += 10;
}
}
You can handle the TextChanged event on each TextBox like so
private void textBox1_TextChanged(object sender, EventArgs e)
{
if (textBox1.Text.Length > 0 && _textbox1IsEmpty)
{
progressBar1.Value += 10;
_textbox1IsEmpty = false;
}
else if (textBox1.Text.Length <= 0)
{
progressBar1.Value -= 10;
_textbox1IsEmpty = true;
}
}
and add a private property in your class
private bool _textbox1IsEmpty = true;
You can make a function to optimize it and don't have duplicate code
Here are a few tips to get you started with WinForms and make it easier to connect multiple TextBoxes with a ProgressBar.
The textboxes (and other controls) that are on a Form can be found in the Controls collection of the form.
All of the textboxes on the form can be obtained with a simple query.
For example, in the form Constructor you could go though all the textboxes and attach a TextChanged handler to each.
public MainForm()
{
InitializeComponent();
foreach (TextBox textBox in Controls.OfType<TextBox>())
{
textBox.TextChanged += onAnyTextChanged;
onAnyTextChanged(textBox, EventArgs.Empty); // Initialize
}
ActiveControl = Fortschrittsanzeige;
}
Multiple text boxes can all point to a common event handler.
System.Linq reduces the amount of code needed for things like matching and sorting.
What we're able to do is perform a validation based on all the textboxes whenever any textbox changes.
const int TEXTBOX_COUNT = 6;
private void onAnyTextChanged(object? sender, EventArgs e)
{
if(sender is TextBox textbox)
{
bool isValid;
if(textbox.PlaceholderText == "PLZ")
{
isValid = textbox.TextLength > 3;
}
else
{
isValid = !string.IsNullOrWhiteSpace(textbox.Text);
}
textbox.BackColor = isValid ? Color.White : Color.LightSalmon;
}
// Use System.Linq to count the number of valid textboxes (based on BackColor).
float countValid =
Controls
.OfType<TextBox>()
.Count(_=>_.BackColor== Color.White);
var pct = countValid / TEXTBOX_COUNT;
Fortschrittsanzeige.Value = (int)(pct * Fortschrittsanzeige.Maximum);
Sendebutton.Enabled = countValid.Equals(TEXTBOX_COUNT);
Fortschrittsanzeige.Visible = !Sendebutton.Enabled;
}
The handler allows for "special cases" and will make the Fortschrittsanzeige go backwards if the changed value is no longer valid.
When all textboxes are valid hide Fortschrittsanzeige and enable Sendebutton.
I have dynamically created array CheckBoxes and I want to do a proper validation if none of them are selected inside the Panel but if I keep on using for loops, the MessageBox keeps on appearing.
Can anyone help me find a way to do this better? I just want to check if a checkbox control is checked inside the Panel and if not, display a messagebox that will say "Select a Checkbox!" only ONCE.
Here is the code that I made for the dynamically created checkboxes in a panel:
for (int z = 0; z <= dataGridView.Columns.Count - 1; z++)
{
chk[z] = new CheckBox();
chk[z].Name = dataGridView.Columns[z].Name;
chk[z].Text = dataGridView.Columns[z].Name;
chk[z].AutoCheck = true;
chk[z].Bounds = new Rectangle(10, 20 + padding + dynamicHeight, 40, 22);
chk[z].Location = new Point(0, dynamicHeight);
chk[z].Size = new Size(120, 21);
panelCol.BackColor = Color.White;
//MessageBox.Show(chk[z].Name + "" + dataGridView.Columns[z].Name);
panelCol.Controls.Add(chk[z]);
//panelCol.AutoScrollMinSize = new Size(0, 100);
dynamicHeight += 20;
panelCol.Size = new Size(120, dynamicHeight);
}
Here is the code that I have came up:
btnValidate.MouseClick += (s, e) => //btnValidate Event
{
for (int z = 0; z < dataGridView.Columns.Count - 1; z++ )
{
if(chk[z].Checked == true)
{
ValidateCheck(dataGridView, chk);
}
else if(chk[z].Checked == false)
{
MessageBox.Show("Select a CheckBox!");
}
}
};
ValidateCheck method:
public static void ValidateCheck(DataGridView dataGridView, CheckBox[] chk)
{
FileStream fs = new FileStream(#"C:\brandon\InvalidColumnCheck.txt", FileMode.OpenOrCreate, FileAccess.Write);
StreamWriter sw = new StreamWriter(fs);
sw.BaseStream.Seek(0, SeekOrigin.End);
StringBuilder sb = new StringBuilder();
decimal num;
sw.WriteLine("----------------------------");
sw.WriteLine("");
for (int j = 0; j < dataGridView.ColumnCount - 1; j++)
{
if (chk[j].Checked == true && chk[j].Name.Contains(dataGridView.Columns[j].Name))
{
string column = chk[j].Name;
for (int k = 0; k < dataGridView.RowCount; k++)
{
if (!Decimal.TryParse(dataGridView.Rows[k].Cells[column].Value.ToString(), out num))
{
if (dataGridView.Rows[k].Cells[dataGridView.Columns[column].Name].Value.ToString() == null || dataGridView.Rows[k].Cells[dataGridView.Columns[column].Name].Value.ToString() == "" || dataGridView.Rows[k].Cells[dataGridView.Columns[column].Name].Value.ToString() == column)
{
}
else
{
//MessageBox.Show("COLUMN" + dataGridView.Columns[j].Name.ToString() + "" + dataGridView.Rows[k].Cells[column].Value.ToString() + " NOT A DECIMAL!");
sb.AppendLine("[Column " + chk[j].Name.ToString().ToUpper() + "] :" + dataGridView.Rows[k].Cells[column].Value.ToString() + " NOT A DECIMAL!");
}
}
}
sb.AppendLine("");
}
}
if (sb.ToString() == null || sb.ToString() == "" || sb.Length < dataGridView.Columns.Count)
{
sw.WriteLine("No Errors!");
sw.WriteLine("");
sw.WriteLine("----------------------------");
MessageBox.Show("No errors!");
Process.Start(#"C:\brandon\InvalidColumnCheck.txt");
}
else if (sb.ToString() != null || sb.ToString() != "")
{
sw.WriteLine(sb.ToString());
sw.WriteLine("----------------------------");
//MessageBox.Show(sb.ToString());
Process.Start(#"C:\brandon\InvalidColumnCheck.txt");
}
sw.Flush();
sw.Close();
}
Here another way to get all Checkboxes from Panel, which are checked (with Linq):
List<CheckBox> selectedItems = panelCol.Controls.OfType<CheckBox>().Where(chk => chk.Checked).ToList();
Please change the validation method like below,
public List<CheckBox> GetSelectedItems()
{
List<CheckBox> selectedList = new List<CheckBox>();
foreach(Control control in panelCol.Controls) // panelCol is your panel
{
if(control is CheckBox)
{
CheckBox chkCtrl = control as CheckBox;
if(chkCtrl.Checked)
{
selectedList.Add(chkCtrl);
}
}
}
return selectedList;
}
btnValidate.MouseClick += (s, e) =>//btnValidate Event
{
List<CheckBox> selectedItems = GetSelectedItems();
if(selectedItems.Count == 0)
MessageBox.Show("Select a CheckBox!");
else{
// Continue with other validation for the selected checkboxes from the list
}
}
Hope it helps!
I keep getting stuck on this part of my program.
whenver i call an listbox.selectitemchange event, i want the proper amount of trackbar and labels to be displayed.
now, it does not work properly.
Some of them get removed when the event is called, some of them don't.
foreach (Label label in Controls.OfType<Label>())
{
if (label.Tag != null && label.Tag.ToString() == "dispose")
{
label.Dispose();
}
}
foreach (TrackBar trackBar in Controls.OfType<TrackBar>())
{
if (trackBar.Tag != null && trackBar.Tag.ToString() == "dispose")
{
trackBar.Dispose();
}
}
for (int i = 0; i < calc; i++)
{
//string[] LineWidthSplitted = lines[lineWidth].Split(' ');
//Int32.TryParse(LineWidthSplitted[2], out WidthValue);
Label Label = new Label();
Label.Name = "TrackbarWidth" + LabelName++;
Label.Tag = "dispose";
Label.Text = "Board -" + LabelName + "- Height:";
Label.Location = new Point(10, 450 + (50 * LabelName));
Label.Size = new System.Drawing.Size(100, 25);
this.Controls.Add(Label);
TrackBar trackBar = new TrackBar();
trackBar.Name = "TrackbarWidth" + trackbarName++;
trackBar.Tag = "dispose";
trackBar.Maximum = 85;
trackBar.Minimum = 65;
trackBar.SmallChange = 5;
trackBar.TickFrequency = 5;
trackBar.Value = 65;
trackBar.Location = new Point(150, 450 + (50 * trackbarName));
trackBar.Size = new System.Drawing.Size(100, 25);
this.Controls.Add(trackBar);
lineWidth += 4;
}
while, when i remove the foreach for the trackbar, all labels get properly displayed.
they all get deleted, en recreated for the pricese amount needed to be created, no exceptions.
Any reason why?
thank you.
Don't use "Dispose" on the labels right away. First remove them. Note that you can't modify the Controls collection inside the foreach so you have to do something like this:
List<Label> itemsToRemove = new List<Label>();
foreach (Label label in Controls.OfType<Label>())
{
if (label.Tag != null && label.Tag.ToString() == "dispose")
{
itemsToRemove.Add(label);
}
}
foreach (Label label in itemsToRemove)
{
Controls.Remove(label);
label.Dispose();
}
If you want to remove all different kinds of controls in one swoop:
List<Control> itemsToRemove = new List<Control>();
foreach (Control ctrl in Controls)
{
if (ctrl.Tag != null && ctrl.Tag.ToString() == "dispose")
{
itemsToRemove.Add(ctrl);
}
}
foreach (Control ctrl in itemsToRemove)
{
Controls.Remove(ctrl);
ctrl.Dispose();
}
I can't test this now, but I think you should also remove the controls from the Form Controls collection where you have added them. By the way, in your case I think you could avoid the OfType extension and use the old fashioned for..loop that will allow to execute just one loop....
for(int x = this.Controls.Count - 1; x >= 0; x--))
{
Control ctr = this.Controls[x];
if (ctr Is Label && ctr.Tag != null && ctr.Tag.ToString() == "dispose")
{
this.Controls.Remove(ctr);
ctr.Dispose();
}
if(ctr Is TrackBar && ctr.Tag != null && ctr.Tag.ToString() == "dispose")
{
this.Controls.Remove(ctr);
ctr.Dispose();
}
}
Notice how removing elements from a collection with a for..loop should be done in reverse order, from the end to start of the collection
My winform has a progress bar which should increase based on the number of files the program is processing. it works fine on one box (win xp) but not the other(winserver 2008). The bar is not filled fully by the time the process ends. Both have the same .net framework 3.5
private void data_process()
{
int progress_num = (100/checkedListBox1.Items.Count);
.......
progressBar1.Value = progressBar1.Value + progress_num;}
do you know why? and do you have better solution?
------this is the new code
private void button1_Click(object sender, EventArgs e)
{
progressBar1.Value = 0;
richTextBox1.Clear();
richTextBox1.Focus();
if (checkedListBox1.CheckedItems.Count < 1)
{
MessageBox.Show("No file is selected", "Warning");
}
else
{
if ((region != null) && (venue != null) && (lhversion != null) && (release_version != null) && (desc != null))
{
progressBar1.Maximum = checkedListBox1.Items.Count + 3;
progressBar1.Step = 1;
//progressBar1.Value = progressBar1.Value + 10;
progressBar1.PerformStep();
login();
//progressBar1.Value = progressBar1.Value + 10;
progressBar1.PerformStep();
data_process();
//progressBar1.Value = progressBar1.Value + 10;
progressBar1.PerformStep();
if (user_in == true)
{
richTextBox1.SelectionColor = Color.Blue;
richTextBox1.AppendText("Done");
}
}
private void data_process()
{
string line;
//int progress_num = (70/checkedListBox1.Items.Count);
foreach (object itemChecked in checkedListBox1.CheckedItems) // for each selected file
{
...
progressBar1.PerformStep();
}
}
I will try to use the native command to increment the progress bar without calculating the increment
(what happens when the items are > 100?)
progressBar1.Maximum = checkedListBox1.Items.Count;
progressBar1.Step = 1;
...
progressBar1.PerformStep();
My program opens a series of forms all over the screen, am I able to code in an escape method, so on typing of the word "test" the program will close?
I was looking at the msdn keypress and how they use a switch, would I use something similar to check for the pressed key and if the correct key is pressed, a counter will increment of the correct key presses until, for "test", 4 will be reached, and if the pressed key is incorrect reset the counter and start over until the right order of keys are entered.
I hope that makes sense :P
public partial class TrollFrm : Form
{
int number = 1; //change to 2 and have the first instance of troll count = number - 1
System.Windows.Forms.Timer myTimer = new System.Windows.Forms.Timer();
public TrollFrm()
{
InitializeComponent();
this.Text = "Trololol - Troll Count: " + number;
startTimer();
}
private void TrollFrm_Load(object sender, EventArgs e)
{
//this.Enabled = false;
}
private void TrollFrm_FormClosing(object sender, FormClosingEventArgs e)
{
e.Cancel = true;
}
public void startTimer()
{
myTimer.Tick += new EventHandler(createForm);
//myTimer.Interval = 500;
myTimer.Start();
}
public void createForm(Object myObject, EventArgs myEventArgs)
{
Form frm = new TrollChildFrm();
Random randomX = new Random();
Random randomY = new Random();
frm.Text = "Trololol - Troll Count: " + number;
int xValue;
int yValue;
number++;
if (number % 2 == 0) //number is even.
{
xValue = (Convert.ToInt32(randomX.Next(1, 1920))) + 200;
yValue = (Convert.ToInt32(randomY.Next(1, 1080))) - 200;
}
else //number is not even.
{
xValue = (Convert.ToInt32(randomX.Next(1, 1920))) - 200;
yValue = (Convert.ToInt32(randomY.Next(1, 1080))) + 200;
}
frm.Show();
frm.Location = new Point(xValue, yValue);
if (number == 20)
{
myTimer.Stop();
}
}
It is an implementation you could use for scenario you described (not tested though):
int exitKeysCount = 0;
private void TrollFrm_KeyDown(object sender, KeyEventArgs e)
{
if (exitKeysCount == 0 && e.KeyCode == Keys.T)
exitKeysCount = 1;
else if (exitKeysCount == 1 && e.KeyCode == Keys.E)
exitKeysCount = 2;
else if (exitKeysCount == 2 && e.KeyCode == Keys.S)
exitKeysCount = 3;
else if (exitKeysCount == 3 && e.KeyCode == Keys.T)
this.Close();
else exitKeysCount = 0;
}
I assumed TrollFrm is your parent form, if they are all invoked somewhere else replace this.Close() with some function in main program function, also TrollFrm needs focus during key presses.
try this parent on your parent form.
int trollCount = 0;
private void TrollFrm_KeyDown(object sender, KeyEventHandler e)
{
if (trollCount == 0 && e.KeyCode == Keys.T)
{
trollCount = 1;
frm.Text = "Trololol - Troll Count:" + trollCount
}
else if (trollCount == 1 && e.KeyCode== Keys.E)
{
trollCount = 2;
frm.Text = "Trololol - Troll Count:" + trollCount
}
else if (trollCount == 2 && e.KeyCode== Keys.S)
{
trollCount = 3;
frm.Text = "Trololol - Troll Count:" + trollCount
}
else if (trollCount == 4 && e.KeyCode== Keys.T)
{
trollCount = 4;
this.Close();
}
else
trollCount = 0;
tell me if you need anything else.