Combobox selects the first item when searching for text - c#

I have a combobox in which I can type in text and it suggests results based on list of items containing that text. Everything seems to be working fine, except when I type in the first letter, the combobox automatically selects the first item in the results list as can be seen in the screenshot (http://prntscr.com/pple6f). I need to press the key again to clear the text field and type in the proper name. Only then the results are correct (http://prntscr.com/pplekc)
I have the following method to check for combobox text update
private void comboBox1_TextUpdate(object sender, EventArgs e)
{
comboBox1.Items.Clear();
listNew.Clear();
var source = new AutoCompleteStringCollection();
foreach (var item in listOnit)
{
if (item.ToLower().Contains(this.comboBox1.Text.ToLower()))
{
listNew.Add(item);
}
}
comboBox1.Items.AddRange(listNew.ToArray());
comboBox1.SelectionStart = this.comboBox1.Text.Length;
Cursor = Cursors.Default;
comboBox1.DroppedDown = true;
}
AutoCompleteMode is set to None, same with AutoCompleteSource.
I need the combobox to start filtering the results as soon as I start typing, not having to press the same letter twice. Are there any other options/properties that I need to check?

Related

Save and load listbox items added by user in c# with windows form app

I want to save listbox items not to a text file, but save them so that when an item is added to the listbox and the application is closed, upon opening the application the item added to the listbox will still be present.
Use case:
User opens application.
User adds item called "Item 1" to listbox using button.
User closes application.
User opens application again and sees that "Item 1" is still in the listbox, and the added item hasn't been lost by the application closing.
I've seen people succeed in doing something like this with textbox data (this video for example: saving user settings), but am having trouble getting it to work with listbox data.
Here's how I attempted to do it myself based on the linked video beginning with the button the user uses to add an item to the listbox:
private void AddTeamButton_Click(object sender, EventArgs e)
{
// add the item to the listbox
listBox1.Items.Add("Example string);
// add the item to the ListBoxStuff settings
Settings.Default["ListBoxStuff"] = Settings.Default["ListBoxStuff"] + "|" + "Example string";
}
Then upon the form loading:
private void Form1_Load(object sender, EventArgs e) // needs to stay
{
// Items from the ListBoxStuff setting is saved as a string - this may be the issue, but am unsure, this gets the values of the settings?
string listboxItems = Settings.Default["ListBoxStuff"].ToString();
// If there are values other than null or empty.
if (listboxItems != null || !listboxItems.Equals(""))
{
string[] separators = { "|" };
// Put the items in a string array, splitting them at the | which means the next item in the string
string[] itemsToAdd = listboxItems.Split(separators, StringSplitOptions.RemoveEmptyEntries);
// Loop through the array
foreach (string i in itemsToAdd)
{
// Add each item to the list box
listBox1.Items.Add(i);
}
}
}
My thinking was that every time a user adds an item to the list, the listboxstuff string has the item added to it with a | inbetween, upon loading, we get this string, split it at every |, and add each item in the newly created array to the listbox, and if it's empty, nothing happens.
But the result is that the item added to the listbox is not there upon reopening the application after adding an item.
Does anyone know how this could be accomplished?
You need to save the settings
private void AddTeamButton_Click(object sender, EventArgs e)
{
// add the item to the listbox
listBox1.Items.Add("Example string);
// add the item to the ListBoxStuff settings
Settings.Default["ListBoxStuff"] = Settings.Default["ListBoxStuff"] + "|" + "Example string";
Settings.Default.Save();
}

C# Winforms: Set text in ComboBox based on selected Item

I'm new to c# and I'm now learning how to trigger events based on some form actions.
This is part of view:
private void comboGoodsName_TextChanged(object sender, EventArgs e)
{
controller.selectName(comboGoodsName.Text);
}
public void nameChanged(object sender, MeasurementEventArgs e)
{
comboGoodsName.TextChanged -= comboGoodsName_TextChanged;
comboGoodsName.Text = e.value;
comboGoodsName.TextChanged += comboGoodsName_TextChanged;
}
And this is part of controller:
public void selectName(string name)
{
model.Name = name.Split('|')[0].Trim();
if (name.Contains(" | "))
{
string code = name.Split('|')[1].Trim();
model.NameCode = code;
}
}
The scenario is as follows:
I want to have a ComboBox with some items in it (doesn't matter what's the source). Items are combination of name and code in following format: NAME | CODE. When I enter some text in ComboBox (type it in), comboGoodsName_TextChanged is triggered, which in turn calls selectName which sets model's property, which in turn raises an event which is observed by nameChanged. This works fine, as expected (puts NAME in ComboBox and CODE to TextBox - not shown as not relevant). Problem shows up when I select item from ComboBox drop-down list. When I select item, instead of showing NAME in ComboBox, I see NAME | CODE.
Edit: In the model, property is set correctly, which I confirmed by printing its value. So, issue is related only to displaying proper value in ComboBox.
Try this:
private void comboGoodsName_SelectedIndexChanged(object sender, EventArgs e)
{
// if combobox has selected item then continue
if (comboGoodsName.SelectedIndex > -1)
{
// split the selecteditem text on the pipe into a string array then pull the first element in the array i.e. NAME
string nameOnly = comboGoodsName.GetItemText(this.comboGoodsName.SelectedItem).Split('|')[0];
// handing off the reset of the combobox selected value to a delegate method - using methodinvoker on the forms main thread is an efficient to do this
// see https://msdn.microsoft.com/en-us/library/system.windows.forms.methodinvoker(v=vs.110).aspx
this.BeginInvoke((MethodInvoker)delegate { this.comboGoodsName.Text = nameOnly; });
}
}

c# confirm each combobox has a unique value selected

I have a winform with a group of comboboxes, all of the comboboxes with the same list items in them.
I need a way to confirm that when the user is done selecting a value in each box that they only selected each list value once.
Ex:
cbox1 cbox2 cbox 3
Item A Item B Item A (this needs to flag an error since Item A is already selected in cbox1)
I was thinking trying to use the selectedvaluecommited action (as after i populate the list I change the selected index to -1 so they all show "empty" to start) but the loop to make it work seems to be eluding me.
background: this is choosing fields to build a spreadsheet and the user needs to choose the field order.
You can do it like this (quick and dirty):
Add SelectedIndexChanged handler for all three comboboxes (in Form_Load in example)
comboBox1.SelectedIndexChanged += CheckComboBoxes;
comboBox2.SelectedIndexChanged += CheckComboBoxes;
comboBox3.SelectedIndexChanged += CheckComboBoxes;
in CheckComboBoxes method do your checking:
private void CheckComboBoxes(object sender, EventArgs e)
{
if (comboBox1.SelectedIndex == comboBox2.SelectedIndex ||
comboBox1.SelectedIndex == comboBox3.SelectedIndex ||
comboBox2.SelectedIndex == comboBox3.SelectedIndex)
MessageBox.Show("comboboxes are not unique");
}
EDIT:
this is approach when having n comboboxes. Put all items into list, select distinct values and compare that distinct count with items count... Something like this:
private void CheckComboBoxes(object sender, EventArgs e)
{
List<string> comboValues = new List<string>();
foreach (Control c in this.Controls)
{
if (c is ComboBox && !string.IsNullOrEmpty((c as ComboBox).SelectedItem.ToString()))
comboValues.Add((c as ComboBox).SelectedItem.ToString());
}
if (comboValues.Distinct().ToList().Count < comboValues.Count)
MessageBox.Show("not all combos are unique");
}
Here's an approach you can take.
To make the affected comboboxes easy to distinguish, put them all in a GroupBox container.
Write a validation method for your group box.
Subscribe to the group box Validating event by attaching it to your validation method.
In your validation method, loop through all the ComboBox controls in the group box and check if there are any duplicates, and issue an error if so.
For example, assuming the group box is called groupBox1:
private void GroupBox1_Validating(object sender, CancelEventArgs e)
{
base.OnValidating(e);
var selectedIndices = groupBox1.Controls.OfType<ComboBox>().Select(item => item.SelectedIndex);
var anyDuplicates = selectedIndices.GroupBy(x => x).Any(x => x.Count() > 1);
if (!anyDuplicates)
return;
MessageBox.Show("There are duplicates!");
e.Cancel = true;
}
And subscribe to the group box Validating event in the Form1 constructor:
public Form1()
{
InitializeComponent();
groupBox1.Validating += GroupBox1_Validating;
}
Sometimes when validating like this, you need to prevent the validation logic from executing if the user clicks the Cancel button. You're supposed to be able to set the CausesValidation property of the Cancel button to false to prevent this, but I find that it doesn't work for me.
Instead, I just use a bool cancelling field which I set to true in the Cancel button handler:
private void cancelButton_Click(object sender, EventArgs e)
{
cancelling = true;
this.Close();
}
bool cancelling;
And then add the following to the start of GroupBox1_Validating():
if (cancelling)
return;
If it is possible to have different UI design then my suggestion goes as under:
Alternative UI Design - A
Create One ListBox ListFieldsOriginal and populate
Create Second ListBox ListUserSelection, keep it empty initially
Provide buttons as under:
Button '>' means add currently selected item from ListFieldsOrginial to ListUserSelection at end; and remove that item from ListFieldsOriginal
Button '<' means remove currenly selected item from lstUserSelection; and add that item back to ListFieldsOriginal (of course at end)
NOTE: If adding item back to ListFieldsOriginal is your requirement then extra coding is required to find its appropriate index in the ListFieldsOriginal.
Alternative UI Design - B
Create One CheckedListBox ListFieldsOriginal and populate
Create one ListBox ListUserSelection, keep it empty initially
Define ItemCheck event handler for ListFieldsOriginal to add/remove items to/from ListUserSelected.
if (e.CurrentValue==CheckState.Unchecked)
{
string item = ListFieldsOriginal.Items[item];
ListUserSelection.Items.Add(item);
}
else
{
string item = ListFieldsOriginal.Items[item];
ListUserSelection.Items.Remove(item);
}

Key Up/Down Selection of Autocomplete list in Textbox C#

In C# Winforms, I have a textbox with AutoCompleteMode. When the user types some letters the suggestion list populates Correctly. However, if an item in list is selected using (Keyboard) UP and Down key it could not navigate through the list of items. it just picks up the first item shown in the list.
On the other hand selection using mouse click works fine. here is my code
private void txtQryName_TextChanged(object sender, EventArgs e)
{
List<string> fullName = _customerBll.NameSuggestor(txtQryName.Text);
AutoCompleteStringCollection source = new AutoCompleteStringCollection();
source.AddRange(fullName.ToArray());
txtQryName.AutoCompleteMode = AutoCompleteMode.Suggest;
txtQryName.AutoCompleteSource = AutoCompleteSource.CustomSource;
txtQryName.AutoCompleteCustomSource = source;
}
The problem with having a key based selection is that it is very sensitive to the number of items it the stack contains. A possible solution could to be to set that KEY_UP and KEY_DOWN only increase/decreases or selects a specific type within the list.
Additionally I believe you can set the textbox to have a specific responds when you press it, you should consider that if for example the user has not choose an item within ( BOOLEAN: false or true) than no items are selected
An example
private void textBox1_KeyPress
(object sender,System.Windows.Forms.KeyPressEventArgs e)
{
// Check for the flag being set in the KeyDown event.
if (nonNumberEntered == true)
{
e.Handled = true;
}
}
https://msdn.microsoft.com/en-us/library/system.windows.forms.control.keydown(v=vs.110).aspx
Here is some useful stuff for you if you want to expand upon this idea. Hope my answer helps

Get Text from DataGridViewComboxBoxCell

I'm trying to retrieve the value of a DataGridViewComboBoxCell in the following way
When adding items to the ComboBox:
public void LoadLayouts()
{
ImmutableSet<string> layoutNames = _store.Current.Keys;
var dgvComboBox = (DataGridViewComboBoxColumn)this.schedulesDataGrid.Columns[1];
foreach (string name in layoutNames)
{
dgvComboBox.Items.Add(name);
}
}
When trying to read back the value:
var combo = (DataGridViewComboBoxCell) this.schedulesDataGrid[args.ColumnIndex, args.RowIndex];
string LayoutChosen = (string)combo.Value;
However, even if I can see that there is a value selected in the ComboBox, the Value comes back as null, and the FormattedValue comes back as "".
I've tried just setting the array of names as my DataSource, but then I'm not sure what to set for my Display and Value Members, considering I only have a single value (the name of the layout)
Thoughts?
At the time you attempt to read the cell's value, the row has not committed changes. If you have row headers visible, you will see the pencil icon on the row that has not been committed. This normally happens after the cell looses focus. You can force the issue by hooking into the in-place editing control combo-box and causing it to post EndEdit when it changes values:
void dgv_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
var comboBox = e.Control as ComboBox;
if (comboBox != null)
{
// remove any handler we may have added previously
comboBox.SelectionChangeCommitted -= new EventHandler(comboBox_SelectionChangeCommitted);
// add handler
comboBox.SelectionChangeCommitted += new EventHandler(comboBox_SelectionChangeCommitted);
}
}
void comboBox_SelectionChangeCommitted(object sender, EventArgs e)
{
// Allow current dispatch to complete (combo-box submitting its value)
// then EndEdit to commit the change to the row
dgv.BeginInvoke(new Action(() => dgv.EndEdit()));
}

Categories

Resources