Autocomplete in windows application - c#

How can i select value in textbox character by character Like HDPOS Autocomplete textbox
I tried
In Page Load
private void loadproductName()
{
DataTable dt = _poshelper.getproductName("Bill_Select_ProductName");
if (dt.Rows.Count != 0)
{
string[] postSource = dt
.AsEnumerable()
.Select<System.Data.DataRow, String>(x => x.Field<String>("UniqueName"))
.ToArray();
var source = new AutoCompleteStringCollection();
source.AddRange(postSource);
txtItemName.AutoCompleteCustomSource = source;
}
}
In Leave
private void txtItemName_Leave(object sender, EventArgs e)
{
if (!string.IsNullOrEmpty(txtItemName.Text))
{
DataSet ds1 = _poshelper.getproductNameExistWhileLeave(txtItemName.Text);
if (ds1.Tables[0].Rows.Count == 0)
{
txtItemName.Text = "";
txtItemName.Focus();
}
else
{
loadLeave(ds1);
txtItemName.Focus();
}
}
}
I need to
If i delete a character using backspace it delete permanently
I need like 2 nd image if i delete mean i need that containt remain in textbox
Update
more clarification, from comments
The String in the textbox it should not be deleted if i press back space Key. Instead it should select each character.Every time i press backspace

Here I'm suggesting changes to make your textbox carry following behavior.
When you don't want "appended suggestion" text (as shown in first image) to be gone when you type backspace in text box,
you can do it these steps
Get Current Textbox text (removed last character as we have back spaced lastly)
Clear Text's Text
Send Text taken text back to textbox
do following change in your code
private void loadproductName()
{
DataTable dt = _poshelper.getproductName("Bill_Select_ProductName");
if (dt.Rows.Count != 0)
{
string[] postSource = dt
.AsEnumerable()
.Select<System.Data.DataRow, String>(x => x.Field<String>("UniqueName"))
.ToArray();
var source = new AutoCompleteStringCollection();
source.AddRange(postSource);
txtItemName.AutoCompleteMode = System.Windows.Forms.AutoCompleteMode.SuggestAppend;
txtItemName.AutoCompleteSource = System.Windows.Forms.AutoCompleteSource.CustomSource;
txtItemName.AutoCompleteCustomSource = source;
}
}
I'm not sure what you are doing in Leave Event. But you can add textBox's KeyUp event, and add code like below in that event.
private void txtItemName_KeyUp(object sender, KeyEventArgs e)
{
// track for backspace
if (e.KeyCode == Keys.Back)
{
if (txtItemName.Text != "")
{
string text = txtItemName.Text.Substring(0, txtItemName.Text.Count() - 1);
txtItemName.Text = "";
txtItemName.Focus();
SendKeys.Send(text);
}
}
}

Related

How to filter ListView by using a ComboBox?

I have a TextBox that searches whatever I have in my ListView. I would like to have a ComboBox that will allow the user to “Show All”, “Show Match” and “Show Non Match” within the ListView depending on search criteria.
private void SearchBtn_Click(object sender, EventArgs e)
{
int count = 0, searchStartIndex = selectedIndexPos = 0;
// Clear previously selected indices
listView.SelectedIndices.Clear();
string target = searchTextBox.Text;
// Search for item with text from the search text box, including subItems, from searchStartIndex, not a prefixSearch
ListViewItem item = listView.FindItemWithText(target, true, searchStartIndex, false);
/*----------------------------------------------------------------------------------------------------*
* While the search results in an item found continue searching. *
*----------------------------------------------------------------------------------------------------*/
while (item != null)
{
count++;
// Update progressBar
progressBar.Value = (int)((float)searchStartIndex / listView.VirtualListSize * 100);
ListView.SelectedIndexCollection indexes = listView.SelectedIndices;
if (!indexes.Contains(item.Index))
{
listView.SelectedIndices.Add(item.Index);
}
/*----------------------------------------------------------------------------------------------------*
* Set the start index to the index after the last found, if valid start index search for next item.*
*----------------------------------------------------------------------------------------------------*/
if ((searchStartIndex = item.Index + 1) < listView.VirtualListSize)
{
item = listView.FindItemWithText(searchTextBox.Text, true, searchStartIndex, false);
// count++;
}
else
{
item = null;
}
}
if (listView.SelectedIndices.Count == 0)
{
MessageBox.Show("Find item with text \"" + searchTextBox.Text + "\" has no result.");
}
else
{
RefilterListView();
listView.EnsureVisible(listView.SelectedIndices[0]);
}
}
I would like to have my items in the 'ComboBox' to help filter my 'ListView'. The "Show All" should display all contents of 'ListView' along with item that was searched, the "Show Match" should show only the searched item removing everything else that doesn't match the search and "Show Non Match" should show all of the contents from 'ListView' that doesn't match the searched item.
I can't do it exactly in your case. But I hope I realize it. I mean this is just a solution. You can customize it for your case.
First of all, put a BindingSource on your Form and bind it to your data:
bindingSource1.DataSource = data;
Then bind your ListView(actually DataGridView) to the BindingSource:
dataGridView1.DataSource = bindingSource1;
And then define an enum like this:
public enum Something
{
ShowMatch = 1,
ShowNonMatch = 2
}
Now, put a ComboBox on your Form and add your options to it:
comboBox1.Items.Add("Show All");
comboBox1.Items.Add("ShowMatch");
comboBox1.Items.Add("ShowNonMatch");
comboBox1.SelectedIndex = 0;
After that, you can catch the selected item in SelectedIndexChanged:
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (comboBox1.SelectedIndex == 0)
bindingSource1.Filter = null;
else
bindingSource1.Filter = $"Name = '{comboBox1.SelectedItem.ToString()}'";
}

Check through selected items in CheckedListBox and show/ hide columns based on values selected

I am using C# and I need some help. I have DataGridView that I would like to filter (show/ hide columns) based on user selection from the CheckedListBox.
Inside the CheckedListBox, I have listed few items and those are the Column Names from the DataGridView:
All these columns are hidden by default.
CheckedListBox items
Now if user selects THERMAL, I would like to show THERMAL Column in DataGridView. If user deselects THERMAL, I would like to hide THERMAL Column in DataGridView. If user selects/ deselects multiple items, I would like to show/ hide all those items from the DataGridView. I hope this makes sense.
Here is the code that I have:
private void CLB_SHOW_HIDE_SelectedIndexChanged(object sender, EventArgs e)
{
string col = "";
for (int i = 0; i < CLB_SHOW_HIDE.CheckedItems.Count; i++)
{
if (col == "")
{
col = CLB_SHOW_HIDE.GetItemText(CLB_SHOW_HIDE.CheckedItems[i]);
this.DGV_FEATURE.Columns[col].Visible = true;
}
else
{
col += ", " + CLB_SHOW_HIDE.GetItemText(CLB_SHOW_HIDE.CheckedItems[i]);
this.DGV_FEATURE.Columns[col].Visible = false;
}
}
}
Here is the problem... If I remove else statement, I can show All the columns properly only if I go from the bottom up (see my picture above). If I go from top to the bottom, only first item would show. Then I would have to deselect that item and select another one in order for it to show.
If I add else statement like in above code, I get this
Error
Can anyone shed some light on this please?
Just figured out... For anyone that might look for solution similar to this, here is the code:
private void CLB_SHOW_HIDE_SelectedIndexChanged(object sender, EventArgs e)
{
int f = 0;
string qry = "";
for (int i = 0; i < CLB_SHOW_HIDE.Items.Count; i++)
{
if (CLB_SHOW_HIDE.GetItemChecked(i))
{
if (f == 1)
{
qry = CLB_SHOW_HIDE.Items[i].ToString();
this.DGV_FEATURE.Columns[qry].Visible = true;
}
if (f == 0)
{
qry = CLB_SHOW_HIDE.Items[i].ToString();
f = 1;
this.DGV_FEATURE.Columns[qry].Visible = true;
}
}
else
{
qry = CLB_SHOW_HIDE.Items[i].ToString();
this.DGV_FEATURE.Columns[qry].Visible = false;
}
}
}
You are looking for ItemCheck event.
For example, let's say, you have added some columns to DataGridView. Then you can setup checkedListBox and add column names to it. Also add an event handler to handle ItemCheck event:
foreach (DataGridViewColumn c in dataGridView1.Columns)
checkedListBox1.Items.Add(c.Name);
checkedListBox1.ItemCheck += CheckedListBox1_ItemCheck;
Then handle ItemCheck event to show or hide columns:
private void CheckedListBox1_ItemCheck(object sender, ItemCheckEventArgs e)
{
var item = checkedListBox1.GetItemText(checkedListBox1.Items[e.Index]);
dataGridView1.Columns[item].Visible = e.NewValue == CheckState.Checked ? true : false;
}

How to add columns and Evaluate the value

I have a datagridview (two columns). Columns 1: Name, Columns 2: Age
And I want add more column name Evaluate behind Columns Age when I press Evaluate button.
Content on each row are Young(Old). Young if Age<40 and Old if Age>40
How I do that?
My code:
OpenFileDialog opd = new OpenFileDialog();
private void btnOpenfile_Click(object sender, EventArgs e)
{
//Open txt file
opd.Filter = "TXT|*.txt";
//Choose File
if (opd.ShowDialog() == DialogResult.OK)
{
lblFilename.Text = opd.SafeFileName;
}
var dulieu = File.ReadAllLines(opd.FileName);
////////////////////
if (dulieu.Count() > 0)
{
foreach (var cellValues in dulieu.Skip(0))
{
var cellArray = cellValues
.Split(new[] {'\t'}, StringSplitOptions.RemoveEmptyEntries);
if (cellArray.Length == dtgBangketqua.Columns.Count)
dtgBangketqua.Rows.Add(cellArray);
}
}
}
My Form
Based on your if (cellArray.Length == dtgBangketqua.Columns.Count) I assume you do not already have a "Evaluate" column within your DataGridView. So first thing to do is add one.
Then loop through each row and obtain the age value.
It originally came in as a string, so, you need to cast it to an int.
Then evaluate the age, I assume you did not mean to exclude people who are exactly 40, so I set that as Old.
Here is the code that should work for your need:
private void btnEvaluate_Click(object sender, EventArgs e)
{
dtgBangketqua.Columns.Add("Evaluate", "Evaluate");
foreach (DataGridViewRow ThisRow in dtgBangketqua.Rows)
{
string strAge = ThisRow.Cells[1].Value as string;
int Age = -1;
if( int.TryParse(strAge,out Age) == true )
{
ThisRow.Cells[2].Value = (Age < 40) ? "Young" : "Old";
}
}
}
Don't forget to mark the answer as accepted if it works for you.

Input a value from a combobox, while committing an Add in DataGridView

Using C# and forms. I have a datagridview which has two of the three fields visible in the table which is editable and addable. The third field is in a combobox.
When updating the database (hitting enter after adding in the empty row) I get an error saying that the third field can't be null. I'd like to have the value in the combobox be used for the third field.
I can't seem to figure it out. Should I be using an event, somehow?
private void cmbMCID_SelectedIndexChanged(object sender, EventArgs e)
{
var cMarks = (from cm in DB.Student_Courses
where cm.CID == Convert.ToInt32(cmbMCID.Text)
select cm).ToList();
Student_Course sc = new Student_Course();
//cMarks.Add(sc);
studentCourseBindingSource.DataSource = cMarks;
sc.CID = Convert.ToInt32(cmbMCID.Text);
//studentCourseBindingSource.ResetBindings(false);
}
I've attempted to added a RowsAdded Event but didn't come out on top.
private void dgvSMarks_RowsAdded(object sender, DataGridViewRowsAddedEventArgs e)
{
if (tabControl1.SelectedIndex == 3)
{
Student_Course sc = new Student_Course();
sc.CID = Convert.ToInt32(cmbMCID.Text);
}
}
Great, OK. so I was doing horrible things - with the combobox. A mix of needing to making a selection in the combobox first (otherwise returned null) and trying to commit what was already in the database.
Needed to create a for loop through the dgv collection, too.
private void dgvSMarks_RowsAdded(object sender, DataGridViewRowsAddedEventArgs e)
{
// if (dgvSMarks.ContainsFocus == true)
// {
// // Get the RowIndex of the CID Cell, and add the combobox MCID value to it
// dgvSMarks.Rows[e.RowIndex-1].Cells[0].Value = Convert.ToInt32(cmbMCID.Text);
// }
var student_course = new Student_Course();
var course = new Course();
//MessageBox.Show("Row Count is " + dgvSMarks.Rows.Count);
for (int i = 1; i < dgvSMarks.Rows.Count; i++)
{
if (i == (dgvSMarks.Rows.Count - 1))
{
student_course.CID = Convert.ToInt32(cmbMCID.Text);
student_course.SID = Convert.ToInt32(dgvSMarks.Rows[i - 1].Cells[1].Value);
student_course.Mark = Convert.ToInt32(dgvSMarks.Rows[i - 1].Cells[2].Value);
DB.Student_Courses.InsertOnSubmit(student_course);
DB.SubmitChanges();
}
}
}
Thanks to the help of my CPI instructors. :)

How to make winforms textbox autocomplete correct capitalisation?

Using a winforms textbox with autocomplete set to SuggestAppend I can type out part of a string and the rest will be suggested to me fine.
If a user types "smi" looking for "Smith, John" and then autocompletes the rest of the string by tabbing then the textbox contains "smith, John". But, if the user clicks on the name then the capitalisation is correct.
Is there a way I can get the autocomplete to re-capitalise the user inputted part of the string when the suggestion is accepted by tabbing?
Pressing tab leads to:
Clicking name leads to (this is what I want):
To handle this situation I handled the textbox Leave event. The idea is to split the text by comma, uppercase the first letter of the resulting strings, then join the strings back together.
private void textBox1_Leave(object sender, EventArgs e)
{
string[] strings = this.textBox1.Text.Split(new char[] { ',' });
for (int i = 0; i < strings.Length; i++)
{
strings[i] = string.Format("{0}{1}", char.ToUpper(strings[i][0]), strings[i].Substring(1));
}
this.textBox1.Text = string.Join(",", strings);
}
Here's the function I came up with the end, it replaces the textbox's content with a line from the AutoCompleteCustomSource of the textbox (sorted alphabetically).
So, this will still work for any case (e.g if user entered "aLLeN" it would still correct to "Allen,Charlie (ID:104)"
private void fixContent()
{
String text = txtAutoComplete.Text;
List<String> matchedResults = new List<String>();
//Iterate through textbox autocompletecustomsource
foreach (String ACLine in txtAutoComplete.AutoCompleteCustomSource)
{
//Check ACLine length is longer than text length or substring will raise exception
if (ACLine.Length >= text.Length)
{
//If the part of the ACLine with the same length as text is the same as text, it's a possible match
if (ACLine.Substring(0, text.Length).ToLower() == text.ToLower())
matchedResults.Add(ACLine);
}
}
//Sort results and set text to first result
matchedResults.Sort();
txtAutoComplete.Text = matchedResults[0]
}
Thanks to OhBeWise I attached this to the textbox leave event:
private void txtAutoComplete_Leave(object sender, EventArgs e)
{
fixContent();
}
But also I needed to cover situations when the autocomplete has been accepted which occur when enter, tab, left and right are pressed. Attaching this to the keydown event doesn't work because I think the autocomplete captures the event beforehand, so I attached to the previewkeydown event:
private void txtAutoComplete_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
Keys key = (Keys)e.KeyCode;
if (key == Keys.Enter || key == Keys.Tab || key == Keys.Left || key == Keys.Right)
{
fixContent();
}
}
simple ;
private void textbox_TextChanged(object sender, EventArgs e)
{
AutoCompleteStringCollection a = new AutoCompleteStringCollection();
a = textbox.AutoCompleteCustomSource;
for (int i = 0; i < a.Count; i++)
{
if (a[i].ToLower() == textbox.Text.ToLower())
{
textbox.Text= a[i].ToString();
break;
}
}
}

Categories