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.
Related
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
}
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.
Most of my dropdown boxes use the SuggestAppend property, meaning when you start typing in the box, it will make a shortlist of the items that match your case. However, if I do this after opening the drawer, this happens:
I have tried using this method, but it closes both instead of just one:
private void cmbLoc_TextChanged(object sender, EventArgs e)
{
if (cmbLoc.Text != "")
{
cmbLoc.DroppedDown = false;
}
}
I am trying to have it so that when I type something into the text box, the original dropdown will disappear, and the SuggestAppend draw will appear. How can I manage this?
It worked if I used KeyDown. Try and tell if that helps
private void cmbLoc_KeyDown(object sender, KeyEventArgs e)
{
var comboBox = (ComboBox)sender;
comboBox.DroppedDown = false;
}
IDE: C#.net, Winforms, .net 4.0
I want to bind a text box with suggestions, suggestions will come from a list, that list is having space separated words for example 'Little Jhon' now with the help of following code I have implemented suggestion functionality, but I want when user type anything suggestions should come from both words, currently it is coming from first word only.
Code:
private void BindTournamentNames()
{
//On Load Code
List<String> lstNames= new List<string>();
lstNames.Add("Little John");
lstNames.Add("Hello Yogesh");
var source = new AutoCompleteStringCollection();
txtBox1.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
source.AddRange(lstNames.ToArray());
txtBox1.AutoCompleteCustomSource = source;
txtBox1.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
txtBox1.AutoCompleteSource = AutoCompleteSource.CustomSource;
}
Now when I am typing in textBox 'Little' it is giving me suggestion, but when I am typing John it is not giving me suggestion, please tell me how to do this.
Well existing autoComplete functionality only supports searching by prefix. I have the same requirement in one of my project. So what i had done is -
Added a ListBox just below the TextBox and set its default visibility to false. Then use the OnTextChanged event of the TextBox and the SelectedIndexChanged event of the ListBox to display and select the items. like this -
Note: Assume your BindTournamentNames() method called in Form's constructor.
protected void textBox1_TextChanged(object sender, System.EventArgs e)
{
listBox1.Items.Clear();
if (textBox1.Text.Length == 0)
{
listBox1.Visible = false;
return;
}
foreach (String s in textBox1.AutoCompleteCustomSource)
{
if (s.Contains(textBox1.Text))
{
listBox1.Items.Add(s);
listBox1.Visible = true;
}
}
}
protected void listBox1_SelectedIndexChanged(object sender, System.EventArgs e)
{
textBox1.Text = listBox1.Items[listBox1.SelectedIndex].ToString();
listBox1.Visible = false;
}
good luck...
I have two Group Boxes grpMeter and grpTag. I have to place grpMeter over grpTag.. both need same location and size..
On button click, I have to make them visible alternately. Is it possible? I tried many times but only 1 group box becomes visible. Maybe because of the overlapping problem. I tried with panel, but the same problem arises. Is there any solution?
public void ShowMeter()
{
grpMeter.Visible = true;
grpTags.Visible = false;
}
public void ShowTag()
{
grpTags.Visible = true;
grpMeter.Visible = false;
}
Place both group boxes next to each other so that they don't overlap and see if it works then. If you made it work, don't move the one group box with the mouse, but select it only and then set the coordinates manually in the Properties list.
That way you can prevent the one group box from accidentially becoming the child of the other group box.
Try this logic inside a button_click event:
private void btn_Click(object sender, EventArgs e)
{
if (grpTags.Visible)
ShowMeter();
else
ShowTag();
}
Try this:
private void button_Click(object sender, EventArgs e)
{
grpMeter.Visible = !grpMeter.Visible;
grpTags.Visible = !grpTags.Visible;
}
See the code below. The button Click will toggle visibilty. Also it's important that you set one of the groupboxes as visible and the other one as invisible in your constructor
using System;
using System.Windows.Forms;
namespace TestForm
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
//This is important. Set one of them to be Visible and the other one to be invisible
grpMeter.Visible = false;
grpTags.Visible = true;
}
private void button1_Click(object sender, EventArgs e)
{
grpMeter.Visible = !grpMeter.Visible;
grpTags.Visible = !grpTags.Visible;
}
}
}
I am not sure but what you are looking for seems like FlowLayoutPanel. Then you can put group boxes next to each other and positioning will be handled automatically. This prevents accidentally putting one GroupBox into another or shifting locations. Also provides an easier working at design time.
One of the good way is to use RadioButton. Take two Radio buttons and place it inside a groupbox.
Something like this would work:
private void rdMeter_CheckedChanged(Object sender, EventArgs e)
{
grpMeter.Visible = rdMeter.Checked;
grpTag.Visible = !rdMeter.Checked;
}
private void rdTag_CheckedChanged(Object sender, EventArgs e)
{
grpTag.Visible = rdTag.Checked;
grpMeter.Visible = !rdTag.Checked;
}