Program for learning foreign words C# - 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.

Related

Winform copy button text to textbox using universal method

So this is a fairly straightforward thing, and I am just curious if there is a better way to do it to save lines of code. For class we are making a teletype machine. Basically there is a textbox, and a series of buttons A-Z and 0-9. When you click the button it adds the corresponding letter/number to the textbox. When you click send, it adds the contents of the textbox to a label and resets the textbox. Everything works and it only took a few minutes to build. However there is a mess of redundant lines and I was curious if there is a way to clean up the code with a method.
This is my current code.
private void btn_A_Click(object sender, EventArgs e)
{
box_UserInput.Text = box_UserInput.Text + "A";
}
As you can see, it is very simplistic and straight forward. Click A, and "A" gets added to the textbox. However the Text property of the button is also just "A" and I want to know if there is a way to just copy the text property of that button and add it to the textbox string.
Something like this, except with a universal approach where instead of having to specify btn_A it just inherits which button to copy based on the button clicked. That way I can use the same line of code on every button.
private void btn_A_Click(object sender, EventArgs e)
{
box_UserInput.Text = box_UserInput.Text + btn_A.Text;
}
You can use this which is more universal as the Control class contains the Text property. Also, using the best practice $"".
private void btn_A_Click(object sender, EventArgs e)
{
box_UserInput.Text = $"{box_UserInput.Text}{((Control)sender).Text}";
}
You can also assign the same event to each button. Create an event, say addControlTextOnClick and assign the same event to each button.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void addControlTextOnClick(object sender, EventArgs e)
{
box_UserInput.Text = $"{box_UserInput.Text}{((Control)sender).Text}";
}
}
You can even shorten this more using this C# construct:
private void addControlTextOnClick(object sender, EventArgs e) =>
box_UserInput.Text = $"{box_UserInput.Text}{((Control)sender).Text}";

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
}

check dropdown menu if matches

Long story short: There are specific tags given (like Pop, Rock, Metal) and the User should write into a textbox and every time he adds a char the given tags are checked if one (or more) matches. At the moment I'm using a combobox with the following code:
private void EnterComboBox_TextChanged(object sender, EventArgs e)
{
List<string> AllTags = new List<string>();
AllTags.Add("Pop");
if (AlleTags[0].ToLower().StartsWith(EnterComboBox.Text.ToLower()))
{
EnterComboBox.Items.Clear();
EnterComboBox.Items.Add("Pop");
EnterComboBox.DroppedDown = true;
}
}
this is working fine but the problem is, that after the first char entered the dropbox drops down and the entered text is marked and will be overwritten when a new char is entered. Any ideas how I could fix this? Every idea is welcome it doesn't have to be a combo box :)!
Edit:
After some more (detailed) research I realized I could explain it like this: Basically I want the combobox the behave like the search-bar from google. The users enters letters and in the dropdown menu are autocomplete suggestions
At the moment I solved it like this:
I placed a textbox in front of a combobox so that only the arrow of the combobx is visible and if you click on it you automatically write in the textbox.
public Form1()
{
InitializeComponent();
EingabeTextBox.AutoSize = false;
EingabeTextBox.Size = new Size(243, 21); //the size of the combobox is 260;21
}
private void EingabeTextBox_TextChanged(object sender, EventArgs e)
{
EingabeComboBox.Items.Clear();
List<string> AlleTags = new List<string>();
AlleTags.Add("Example");
if (AlleTags[0].ToLower().StartsWith(EingabeTextBox.Text.ToLower()))
{
EingabeComboBox.Items.Add(AlleTags[0]);
EingabeComboBox.DroppedDown = true;
}
}
For me it would work like this. I hope I can help someone else with this too, but I am still open for any better ideas :)!
Changing the ComboBox entries while typing into it obviously creates undesired interferences. Instead combine a TextBox and a ListBox.
private bool changing;
private void TextBox_TextChanged(object sender, EventArgs e)
{
if (!changing) {
changing = true;
try {
// manipulate entries in the ListBox
} finally {
changing = false;
}
}
}
private void ListBox_IndexChanged(object sender, EventArgs e)
{
if (!changing) {
changing = true;
try {
// Put selected entry into TextBox
} finally {
changing = false;
}
}
}
The changing guard makes sure that the ListBox does not influence the TextBox while you are entering text into the TextBox and vice versa.
The try-finally ensures that the guard will be reset in any circumstances, even if an exception should occur.

Activate a textbox automatically when user starts typing

I want to activate a textbox when users starts typing in my Windows 8.1 Store app.
I tried handling KeyDown event of Page, something like this code:
private void pageRoot_KeyDown(object sender, KeyRoutedEventArgs e)
{
if (SearchBox.FocusState == Windows.UI.Xaml.FocusState.Unfocused)
{
string pressedKey = e.Key.ToString();
SearchBox.Text = pressedKey;
SearchBox.Focus(Windows.UI.Xaml.FocusState.Keyboard);
}
}
But the problem is e.Key.ToString() always returns capital english character of the pressed key, while user might be typing in another language. For example, the Key D types ی in Persian keyboard, and user might want to type in Persian, but e.Key.ToString() will still return D instead of ی.
Also I tried making that textbox always focused (my page contains some gridviews and so on, and a textbox) and while this solution works on PCs, it makes the on-screen keyboard to always appear on tablets.
So, what should I do? Is there any way to get the exact typed character in KeyDown event?
As Mark Hall suggested, It seemed that CoreWindow.CharacterReceived event can help solving this issue.
So, I found the final answer here.
This is the code from that link:
public Foo()
{
this.InitializeComponent();
Window.Current.CoreWindow.CharacterReceived += KeyPress;
}
void KeyPress(CoreWindow sender, CharacterReceivedEventArgs args)
{
args.Handled = true;
Debug.WriteLine("KeyPress " + Convert.ToChar(args.KeyCode));
return;
}
But this event will fire anywhere independent of current active page. So I must remove that event when user navigates to another page, and add it again when user comes back.
Update: I also had to move the cursor of the textbox to the end of the text, so user can write naturally. Here's my final code:
private void KeyPress(Windows.UI.Core.CoreWindow sender, Windows.UI.Core.CharacterReceivedEventArgs args)
{
if (SearchBox.FocusState == Windows.UI.Xaml.FocusState.Unfocused)
{
SearchBox.Text = Convert.ToChar(args.KeyCode).ToString();
SearchBox.SelectionStart = SearchBox.Text.Length;
SearchBox.SelectionLength = 0;
SearchBox.Focus(FocusState.Programmatic);
}
}
private void pageRoot_GotFocus(object sender, RoutedEventArgs e)
{
Window.Current.CoreWindow.CharacterReceived += KeyPress;
}
private void pageRoot_LostFocus(object sender, RoutedEventArgs e)
{
Window.Current.CoreWindow.CharacterReceived -= KeyPress;
}

Writing a method to serve slightly different scenarios 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.

Categories