Writing a method to serve slightly different scenarios C# - c#

I struggled with what to title this as but hopefully I can explain a little better here. I am trying to write a program that will track an assembly through a 6 station assembly line. At each station, the operator will hit a button (such as station1start, station1stop, station2start, etc) and the button press event will send the timestamp to a database and also update the form visually by moving the traveling id number to the next station. I have this all working for the first couple of stations but I'm wondering if there is a way to use the same method for each station. For example have a method such as
void updateStart(int station_num)
where the station ID would be an argument but otherwise the method could be used for all of the stations. I know that variables in C# cannot be dynamically changed but am curious if there is another way to make this code cleaner. It seems like bad programming to have 6 methods almost identical. Especially if we were to add another 6 stations. See the screenshot of the form and my example code below of the button that the operator would hit when they started at station 2. Any help would be greatly appreciated!
http://i.stack.imgur.com/Ddxww.png
private void Station2Start_Click(object sender, EventArgs e)
{
Station2Label.Text = Station1Label.Text;
Station1Label.Text = "";
Station1Status.Text = "";
Station2Status.Text = "IN PROGRESS";
addTimeToDb(2);
}

The question is somewhat unclear but I believe it is:
I have the following code:
private void Station2Start_Click(object sender, EventArgs e)
{
Station2Label.Text = Station1Label.Text;
Station1Label.Text = "";
Station1Status.Text = "";
Station2Status.Text = "IN PROGRESS";
addTimeToDb(2);
}
private void Station3Start_Click(object sender, EventArgs e)
{
Station3Label.Text = Station2Label.Text;
Station2Label.Text = "";
Station2Status.Text = "";
Station3Status.Text = "IN PROGRESS";
addTimeToDb(2);
}
And so on, repeated many times with minor substitutions. How do I "DRY out" this code? (That is Don't Repeat Yourself.)
When you create the labels and status boxes put them in an array:
private Label[] stationLabels;
private Label[] statusLabels;
...
// in your form initialization after the creation of the labels:
stationLabels = new [] { Station1Label, Station2Label, Station3Label, ...
// and similarly for status labels.
Now write
private void StationClick(int station)
{
stationLabels[station-1].Text = stationLabels[station-2].Text;
... and so on
And then each method becomes
private void Station2Start_Click(object sender, EventArgs e)
{
StationClick(2);
}
private void Station3Start_Click(object sender, EventArgs e)
{
StationClick(3);
}
And so on.

Related

C# communication between forms bug

I'm working on a GUI for an admin interface for management of a student complex. Currently the GUI has a listbox with predefined 6 rules for the students. In the beginning of the code, I add them to a list
private void Form1_Load(object sender, EventArgs e)
{
foreach (string rule in lbRules.Items)
ruleList.Add(rule);
}
Then, the GUI provides the admin with an option to modify the rules. To do so he selects a rule from the listbox and clicks a "Modify" button, which opens another form:
private void BtnModify_Click(object sender, EventArgs e)
{
if (lbRules.SelectedItems.Count > 0)
{
selectedRule = lbRules.SelectedItem.ToString();
selectedIndex = lbRules.SelectedIndex;
selectedRuleNumber = selectedRule.Substring(0, 3);
selectedRule = selectedRule.Substring(6);
var rulesForm = new Rules();
rulesForm.Show();
}
}
On the second form load event I get the rule's text and number:
private void Rules_Load(object sender, EventArgs e)
{
tbRule.Text = Form1.selectedRuleNumber;
tbModifyRule.Text = Form1.selectedRule;
}
The text gets added to a RichTextBox, from where the rule can be edited.
Then the admin clicks a "Save" button, which gets the edited text from the RichTextBox(tbModifyRule) and adds it to a static ruleList in form1, sets a static boolean from form1 to true. Afterwards the second form gets closed:
private void BtnSave_Click(object sender, EventArgs e)
{
saveRule = Form1.selectedRuleNumber + " - " + tbModifyRule.Text;
Form1.ruleList.Insert(Form1.selectedIndex, saveRule);
Form1.ruleList.RemoveAt(Form1.selectedIndex+1);
Form1.formOpen = true;
this.Dispose();
}
At this point we are back to form1, in which we have a timer with timer_tick event. In there we check whether the boolean formOpen is true (which it is set before closing form2). Inside the if statement we clear the listbox and add each rule from the ruleList (previously edited in form2) to the listbox, then sets the formOpen back to false so it doesn't get executed all the time:
if (formOpen)
{
lbRules.Items.Clear();
foreach (string item in ruleList)
lbRules.Items.Add(item);
}
formOpen = false;
Now this is really weird, and at this point makes absolutely no sense to me, since I tried debugging it for over an hour, trying different ways, which also led me to mysterious wonders of WHY TF IT WORKS WHENEVER IT WANTS...
So this works randomly, like it would work the first time, the second and third times it won't. Or vice versa. It's all random.
Strangely, I tried adding a breakpoint on the
lbRules.Items.Add(item);
in the foreach loop, so it stops on each item. And I actually saw the changed rule getting added from the ruleList into the listBox, however in the end it was not there.
And weirdly enough, I also tried adding the text from form2 in the listBox in form1, without using a list, but for whatever odd reason, I use the int selectedIndex, which gets the index of the selected item from the BtnModify_Click event to insert the text in that particular index, but this very index gets RANDOMLY set to bloody 0 after form2 closes.
hence, it again works from time to time, because at some tries it doesn't get set to 0 and it works.
if (formOpen)
{
selectedRule = Rules.saveRule;
lbRules.Items.Insert(selectedIndex, selectedRule);
lbRules.Items.RemoveAt(selectedIndex+1);
}
formOpen = false;
I don't assign value to this integer ANYWHERE else in the code.
I really tried digging some sense, but I hit a solid hard rock.
Any help appreciated!
And thanks for the time!
edit1:
as requested - rest of the timer method
private void Timer1_Tick(object sender, EventArgs e)
{
foreach (string text in ws.messages)
message = text;
if (ws.messages.Count > 0)
{
if (message.Contains("comp"))
{
Complaints();
message = String.Empty;
ws.messages.Clear();
}
}
if (formOpen)
{
lbRules.Items.Clear();
foreach (string item in ruleList)
lbRules.Items.Add(item);
}
formOpen = false;
}
I would change your code to the following:
if (formOpen)
{
formOpen = false;
lbRules.Items.Clear();
foreach (string item in ruleList)
lbRules.Items.Add(item);
}
The issue with having the formOpen = false; outside the if statement is that there is a chance that once the user clicks the Save button the timer could be about to execute the formOpen = false instruction setting it to false making the code inside the If statement to never be executed.
I truly believe this is not random but just a timing issue due to complicated logic.
If I were you, I'd do a couple things:
Use a separate class for data exchange between forms, avoid using public static (I assume) form members for this.
Instead of a timer, subscribe to the Form.Closed event of RulesForm
This might make code flow a bit more predictable and allow you to find errors more easily.
Better yet, use the following pattern:
class Form1
{
private void BtnModify_Click(object sender, EventArgs e)
{
var ruleData = ..... //get current rule data
var rulesForm = new Rules();
rulesForm.SetData(ruleData); //pass initial state to the form
rulesForm.SaveChanges = this.ApplyRules; //pass a method which will be called on save
rulesForm.Show();
}
private bool ApplyRules(RuleData ruleData)
{
//do whatever you like with the rules here
return true;
}
}
class RuleForm
{
public void SetData(RuleData ruleData)
{
//initialize fields, etc
}
public Func<RuleData, bool> SaveChanges { get; set; }
private void BtnSave_Click(object sender, EventArgs e)
{
var ruleData = .... //get data from form fields
if(this.SaveChanges(ruleData))
this.Close();
}
}
class RuleData
{
//whatever data you need
}

Program for learning foreign words C#

I am in the process of writing a vocabulary program. C # Windows Form.
Description of the program operation:
Use the buttons to select the location of text files with the words "PL" and "ENG". (two separate files)
Click the start button to start the program
the first word from the board appears in the label
I'm translating the word into the textbox and the Messagebox "OK" or "WRONG" pops up
And here a problem arises. The program instead of every time I wait until I introduce a new word to the textbox, it loops, the questions in the label are changed and MessageBox displays.
How best to do this to make the program work correctly? `` `[
private void sprawdzButton_Click(object sender, EventArgs e)
{
BazaSlow.bazaPolskichSlowek = _fileReader.Read(adresPlikuPL);
BazaSlow.bazaAngielskichSlowek = _fileReader.Read(adresPlikuANG);
string odpowiedz = odpTextBox.Text;
int i = 0;
while (i < BazaSlow.bazaPolskichSlowek.Length)
{
trescSlowkaLabel.Text = BazaSlow.bazaPolskichSlowek[i];
if (odpowiedz.Equals(BazaSlow.bazaAngielskichSlowek[i].ToLower()))
{
MessageBox.Show("OK");
}
else
{
MessageBox.Show("ŹLE");
}
i++;
}
}
This approach will not quite work.
If you use WinForms then you can do it via events. I'll quickly use english variable names since I don't speak your language.
This could be one approach to do it: I used the "TextChanged" event from the textBox.
string[] wordsLanguage1;
string[] wordsLanguage2;
int currentIndex = 0;
private void Form1_Load(object sender, EventArgs e)
{
wordsLanguage1 = System.IO.File.ReadAllLines("somePath1");
wordsLanguage2 = System.IO.File.ReadAllLines("somePath2");
}
private void ReportAndCheckInput(string input)
{
if (input.ToLower().Equals(wordsLanguage2[currentIndex].ToLower())) {
//right translation
currentIndex++;
label1.Text = wordsLanguage1[currentIndex];
textBox1.Text = "";
}
else
{
//wrong translation
}
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
ReportAndCheckInput(textBox1.Text);
}
Now this approach uses the TextChanged event. So the ReportAndCheckInput method will be called on every text-change. That means that your Feedback would pop up on every keystroke which would not be nice. You could use any other event instead of TextChanged. For example a button click. Another solution would be to use a label for your feedback and not a message box. Then the user would never have to click anything but woudl instantly see whether or not he was correct.

System.FormatException occurred in mscorlib.dll when converting it int32

I know, i know there are lots and lots of questions asking on here about this error, each with their own response, but its easier to work off a response regarding your own code rather than someone else's
I have been working on this program for some time for a college assignment, and as soon as i started putting in the class to calculate the totals of things it now crashes,
I don't know where to look so i'll post my main code
enter code here
namespace Till
public partial class MainWindow : Window
{
Calculator calc = new Calculator();
public MainWindow()
{
InitializeComponent();
}
public bool User;
public bool tillopen = false;
private void button_Click(object sender, RoutedEventArgs e)
{
//button clone thingy
Button btn = (Button)sender;
label.Content = label.Content + btn.Content.ToString();
Console.Beep(); // makes the buttons beep
}
private void clear_Click(object sender, RoutedEventArgs e)
{
// Clear
label.Content = "";
}
private void Button_Submit_Click(object sender, RoutedEventArgs e)
{
// submit
listView.Items.Add(label.Content);
label.Content = "";
calc.setSoldItems(Convert.ToInt32(label.Content)); /// it breaks on this line///
}
private void button13_Click(object sender, RoutedEventArgs e)
{
//void sale
label.Content = "";
listView.Items.Clear();
}
private void button15_Click(object sender, RoutedEventArgs e)
{
//pound
label.Content = "1.00";
}
private void button12_Click(object sender, RoutedEventArgs e)
{
//till open close
tillopen = true;
}
private void button16_Click(object sender, RoutedEventArgs e)
{
Login m = new Login();
m.Show();
this.Close();
}
private void button14_Click(object sender, RoutedEventArgs e)
{
label.Content = "2.00"; // 2 pound
}
private void button17_Click(object sender, RoutedEventArgs e)
{
label.Content = calc.finish();
}
}
I have tried to re-create the error in another WPF (converting a to an int32) and it works fine, i know this is an issue with my code itself, i have tried using other machine and using different versions of visual studio itself, so we came to the assumption its this code itself and not a broken dll file
So before I sit down with my Teacher and spend all day going though my code step by step im asking around for help in order to save both of our time, This assignment is due in in 3 weeks, and it decides to break on me now.
thankies
To replicate this error, i press a number button on my Windows form, them hit the submit button i created (which starts the conversion) If a copy of my class which handles all of this is needed im happy to post it
In the method button_click, you have assigned value as
label.Content = label.Content + btn.Content.ToString();
which is a string value to the label and the values are concatenated instead of add.
and when you are reading it, you are converting it in Int32. which will give exception as it will not contain any integer value to it.
You can add the value like this:
label.Content = (Convert.ToInt32(label.Content) + Convert.ToInt32(btn.Content)).ToString();
and check before converting if the label has blank values in it, if it has do not convert them, and only convert the value if it has some values it will not give any error. Also do not assign any values other that numerical digits.
You are calculating:
Convert.ToInt32(label.Content)
but on the line before you set:
label.Content = "";
so this means you are calculating
Convert.ToInt32("")
which gives you a FormatException.
Perhaps you should use the value of label.Content before you overwrite it?

Set a limit on the amount of numbers that can be entered into a "masked textbox"

I am still learning the basics with C# and i am having some trouble. I have been searching the internet for about 3 hours now for an answer on how to set a limit on the amount of characters(in this case it will be limited to a 3 digit integer) a user can enter into a "masked Textbox". I have come across a few different kinds of code, but when i run the program i am still able to enter in as many characters i want. If there is no argument i can add on to do this (meaning i will have to set a loop to check every time) please let me know. I am struggling to learn. Here is the small piece of code that i am attempting to work on.
private void mtbMales_MouseClick(object sender, EventArgs e)
{
mtbMales.Text = "";
mtbMales.SelectionStart = 0;
mtbMales.MaxLength = 3;
mtbMales.Mask = "000";
}
private void mtbFemales_MouseClick(object sender, EventArgs e)
{
mtbFemales.Text = "";
mtbFemales.SelectionStart = 0;
mtbFemales.MaxLength=3;
mtbFemales.Mask = "000";
}
Just set the Mask Property of the masked text box to OOO in the design mode, and you're done.
If you want to set it programmically, set it in the form load event (Double click the form in Design mode)
private void Form1_Load(object sender, EventArgs e)
{
mtbMales.MaxLength = 3;
mtbMales.Mask = "000";
}

StatusLabel - how to reset, or allow status text to time out or fade away

I have a tabbed form with a StatusStrip at the bottom, which includes a StatusLabel. I want to use this status label for various actions ("1 record updated" etc). It is simple enough to create specific events to set the label's text property.
But how best to reset the status to blank? The user could perform any number of other operations where the status is no longer meaningful (going to another tab, clicking other buttons etc.).
It is not feasible to create all the possible events to reset the status message. Is there a way to incorporate some type of timer so that the message fades out after several seconds? Has anyone else found a good solution for this?
Is it truly important to clear the status though? There are plenty of products which will keep their status label unchanged until the next status event occurs. Visual Studio is a good example of this. It may be worth simplifying your scenario and taking this approach.
If you do want to clear the status after an event I think the most maintainable way to do this is with a Timer. Essentially clear after a few seconds when the status is set
Timer m_timer;
void SetStatus(string text) {
m_statusLabel.Text = text;
m_timer.Reset();
}
void OnTimerTick(object sender, EventArgs e) {
m_statusLabel.Text = "";
m_timer.Stop();
}
Yes a timer would work for this to clear it. Here is an example of one I've knocked together.
public partial class Form1 : Form
{
private System.Timers.Timer _systemTimer = null;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
_systemTimer = new System.Timers.Timer(500);
_systemTimer.Elapsed += _systemTimer_Elapsed;
}
void _systemTimer_Elapsed(object sender, ElapsedEventArgs e)
{
toolStripStatusLabel1.Text = string.Empty;
_systemTimer.Stop(); // stop it if you don't want it repeating
}
private void button1_Click(object sender, EventArgs e)
{
toolStripStatusLabel1.Text = "random text just as an example";
}
private void button2_Click(object sender, EventArgs e)
{
_systemTimer.Start();
}
}
Assume button1 is your action to update the status, and button2 is just a random way to start the timer (this can be however you want to start it, I've only used another button click as an example). After the set amount of time passes the status label will be cleared.

Categories