I'm using an Enum within a ComboBox. I want it to allow editing, so that the user can type things in it. I converted the Enum to a string[] arrayItems while listItems is the length of the Enum list.
Now I want to check the users text input: If it isn't listed, it should show a message that the item is not listed there.
But for my code (below) it shows me a error multiple times:
// Converted enum to string[] before
for (int i = 0; i < listItems; i++)
{
if (comboBox1.Text != arrayItems[i])
{
message = string.Format("Sorry! " + comboBox1.Text + " not found.");
}
}
This shows error every time I start it as it iterates through each and every element in the list. I want that if this could check the whole Enum list and give the error once in case of wrong input.
You can change your loop as
bool ok = false;
for (int i = 0; i < listItems; i++)
{
if (comboBox1.Text == arrayItems[i])
{
ok=true;
break;
}
}
if(ok==false)
{
message = string.Format("Sorry! " + comboBox1.Text + " not found.");
}
if(arrayItrmd.Contains(combobox1.Text))
{
//logic if trur
}
You can use LINQ's All for this. As the name implies, it will only be true if all elements correspond to your query. It's basically the equivalent of !Any
if (arrayItrmd.All(item => item != comboBox1.Text))
{
message = string.Format("Sorry! " + comboBox1.Text + " not found.");
}
This means "If each element from arrayItrmd is not equal to comboBox1's text, assign the message."
You can ignore the use of a loop
if(tmpImageArray.FirstOrDefault(a => a == comboBox1.Text) == default(String))
{
message = comboBox1.Text + " not found";
}
else{
message = comboBox1.Text + " found";
}
I have solved this problem like this,
First my enum that I will bind to my combobox
public enum comboboxVals
{
one, two, three
}
Then set my combobox's datasource like this
comboBox1.DataSource = Enum.GetNames(typeof(comboboxVals));
and then implemented code in one of my combobox events to check if the value is valid like combobox Leave, Validating and Validated events..
private void comboBox1_Validating(object sender, CancelEventArgs e)
{
var cbx = sender as ComboBox;
if (!Enum.IsDefined(typeof(comboboxVals), cbx.Text))
{
MessageBox.Show(cbx.Text + " not in the list");
e.Cancel=true;
}
else
{
// Implement your logic here
}
}
Related
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()}'";
}
I am an automation tester and I have automated the dropdown selection. I have a set of elements in a dropdown . I am storing all the values in the dropdown using the below code(I am using the Xpath)
ListItem item = "/container[#caption='selectbox']/listitem[#text='" + comboItem + "']";
As a recent change, our developers have added null value for the first element of a dropdown. Because of this I am getting error in my code and so dropdown selection functionality is not working. By any way is there a chance to catch the null value stored in the List and continue to the store the next value of the dropdown in the list.
I am using the below code to select an element from a dropdown and I am getting error in the above line that has been described in main part of question.
public void SelectfromSelecttag(SelectTag selectTag, string comboItem)
{
try
{
int attemptsToSelect =0;
int maxAttemps = 3;
while(attemptsToSelect != maxAttemps)
{
selectTag.EnsureVisible();
selectTag.Click(Location.CenterRight, 1000);
ListItem item = "/container[#caption='selectbox']/listitem[#text='" + comboItem + "']";
Delay.Milliseconds(1000);
item.Select();
item.MoveTo();
item.Click();
string itemtext = item.Text;
if(itemtext == comboItem)
{
break;
}
else
{
attemptsToSelect++;
}
}
Thread.Sleep(3000);
}
catch (Exception e)
{
Logger.Instance.ErrorLog ("Unable to find Select Item: " + comboItem + e.Message);
}
}
I want to search a listbox for a object value i made. This is the override string. This is how items are added into the listbox.
public override string ToString()
{
string reservatiestring;
reservatiestring ="Kamer: " + roomNumber + " Op datum: " + datum + " Aantal personen: " + personen.Count + " Naam: " + reservatienaam;
return reservatiestring;
}
I'd now like to search in my listbox for results while searching for a specific roomNumber. All the roomNumbers are saved in a combobox. This is what i have currently:
private void buttonSearch_Click(object sender, EventArgs e)
{
foreach (var item in listBox1.Items)
{
for (int i = listBox1.Items.Count - 1; i >= 0; i--)
{
if (listBox1.Items[i].ToString().ToLower().Contains(comboBox1.SelectedText.ToLower()))
{
listBox1.SetSelected(i, true);
}
else
{
MessageBox.Show("error");
}
}
This only selects one result though and its not specified to the roomNumber object only. When i put in the foreach to make it select multiple items, my program failed and i got the following error:
The list that this enumerator is bound to has been modified. An enumerator can only be used if the list is not changed
Extra info as asked for!
This is where i add the info to the listbox:
private void btnReserve_Click(object sender, EventArgs e)
{
Reservations reservatie = new Reservations();
reservatie.roomNumber = Convert.ToInt32(numericUpDownroom.Value);
reservatie.datum = dateTimePicker1.Value;
reservatie.reservatienaam = textBoxName1.Text;
for (int i = 0; i <= personcount; i++)
{
Person persoon = new Person();
persoon.naam = textBoxName1.Text;
persoon.leeftijd = Convert.ToInt32(numericUpDownAge1.Value);
reservatie.personen.Add(persoon);
}
if (!comboBox1.Items.Contains(reservatie.roomNumber))
{
comboBox1.Items.Add(reservatie.roomNumber);
}
else
reservaties.Add(reservatie);
listBox1.FormattingEnabled = false;
listBox1.Items.Add(reservatie.ToString());
The error: the error when it pops up. The dutch additional information is the initial error message.
I don't see why you need a foreach to multi select in your case especially that you are not using the "var item" anywhere in the code.
However, the exception might happen if the "SetSelected" implementation is doing some changes internally to the items.
Make sure you have configured your list for multi-select
// Set the selection mode to multiple and extended.
listBox1.SelectionMode = SelectionMode.MultiExtended;
Remove the foreach. (If you still need another loop, replace your foreach with a "for")
Check the below documentation link which has v. good example of multi-select ListBox:
https://msdn.microsoft.com/en-us/library/system.windows.forms.listbox.items(v=vs.110).aspx
I have a datagridview and it is bound to a database. When i click one of its cell to update its value, actually what happens is that the value of that particular cell is updated but the values of the same row is also updated to null. What do i do so that the values of the same row does not updates to null but it remains as they are?
My Code :
int quantityColumnIndex = 0;
string particularColumnIndex = "";
int rateColumnIndex = 0;
private void buttonUpdate_Click(object sender, EventArgs e)
{
{
string SQL = "Update OrderLineItems set Quantity = " + quantityColumnIndex +
", Particular = '" + particularColumnIndex +
"', Rate = " + rateColumnIndex + " where OrderLineItems.Id = " + Id;
result = dm.ExecuteActionQuery(SQL);
}
if (result > 0)
{
MessageBox.Show("Record Updated Successfully", "Update Record", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
private void dataGridViewOrderDetails_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex == 1)
{
quantityColumnIndex = Convert.ToInt32(dataGridViewOrderDetails.Rows[e.RowIndex].Cells[e.ColumnIndex].Value);
}
if (e.ColumnIndex == 2)
{
particularColumnIndex = dataGridViewOrderDetails.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString();
}
if (e.ColumnIndex == 3)
{
rateColumnIndex = Convert.ToInt32(dataGridViewOrderDetails.Rows[e.RowIndex].Cells[e.ColumnIndex].Value);
}
}
Help required
One solution is to change quantityColumnIndex, particularColumnIndex and rateColumnIndex to nullables and change the query so it doesn't update the columns that weren't changed.
I guess you know which is the row that's being edited. If you don't, then you will have troubles if the user changes the values but selects another row. So, if you know the row, I think the better choice is to change the query to:
var row = dataGridViewOrderDetails.Rows[rowNumber];
string SQL = "Update OrderLineItems set Quantity = " + Convert.ToInt32(row.Cells[1].Value); + ", Particular = '" + row.Cells[2].Value.ToString() + "', Rate = " + Convert.ToInt32(row.Cells[e.ColumnIndex].Value)+ " where OrderLineItems.Id = " + Id;
result = dm.ExecuteActionQuery(SQL);
Have you tried to assign a new value ?
if (e.ColumnIndex == 1)
{
dataGridViewOrderDetails.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = 5;
}
However if the datagrid is bound to a datatable you have to update the value in the datatable.
Why are you casting the result of the Value property to the DataGridViewCell type? The Value property gives you the value of the cell, not the cell itself. The code is wrong; make sure you understand the object model of the DataGridView control.
Try the following code instead:
if (e.ColumnIndex == 1)
{
// Get a reference to the cell of interest.
DataGridViewCell quantity = dataGridViewOrderDetails.Rows[e.RowIndex].Cells[e.ColumnIndex];
// Update its value.
quantity.Value = 100; // or whatever your new value is
}
Can you check whether the same thing happening in your database as well ( changing all values to null except the one you edited).
Check the values of the variables(quantityColumnIndex,particularColumnIndex and rateColumnIndex ) at run time on line "result = dm.ExecuteActionQuery(SQL);".
I think all the values will be null except the one you just edited because you are changing the value of only one variable in dataGridViewOrderDetails_CellValueChanged(..) method. So you need to assign values to all the variables in the dataGridViewOrderDetails_CellValueChanged function.
private void buttonUpdate_Click(object sender, EventArgs e)
{
if ((dataGridViewOrderDetails.Rows.Count - 1 > RowCount) == false)
{
for (int i = 0; i < dataGridViewOrderDetails.RowCount - 1; i++)
{
string SQL = "Update OrderLineItems set Quantity = " + dataGridViewOrderDetails.Rows[i].Cells[1].Value +
", Particular = '" + dataGridViewOrderDetails.Rows[i].Cells[2].Value + "', Rate = " + dataGridViewOrderDetails.Rows[i].Cells[3].Value + " where OrderLineItems.Id = " + dataGridViewOrderDetails.Rows[i].Cells[0].Value;
result = dm.ExecuteActionQuery(SQL);
}
}
There is a problem in a query. This has been solved :)
I have a CheckedListBox that has X number of items. These items are placed there at runtime. These items are supposed to represent reports that can be displayed in the DataGridView. What I need to do now is display the record count for each report in parenthesis right next to the report name. I tried, not for too long, to edit the actual name of the item but couldn't find out how to do it. So then, I brute forced it. Saved the items to an array, cleared the items, appended the record counts to each item in the array, created new items. Well, this has caused issues because now it's not retaining my checks and the reason why is because whenever I generate the reports, I clear the items and recreate them. Well, rather than doing another foreach loop to save the checked status, does anyone know of a way to change the text of existing items in a CheckedListBox?
Here is the code I currently have:
In the MainForm.Designer.cs:
this.clbReports.Items.AddRange(new object[] {
"Report 1",
"Report 2",
"Report 3",
"Report 4",
"Report 5",
"Report 6",
"Report 7",
"Report 8",
"Report 9",
"Report 10",
"Report 11"});
And it looks like:
And I want it to look like (but there won't all be 0's):
Here is the SelectedIndexChanged function:
private void clbReports_SelectedIndexChanged(object sender, EventArgs e)
{
string strCheckBox = clbReports.SelectedItem.ToString();
bool bShowAllIsChecked = clbReports.GetItemChecked(clbReports.FindString("Show All Error Reports"));
bool bSelected = clbReports.GetItemChecked(clbReports.FindString(strCheckBox));
int nIndex = -1;
if (strCheckBox.Contains("Show All Error Reports"))
{
foreach (string str in _strReports)
{
if (!str.Contains("Show All Error Reports") && !str.Contains("Show Tagged Records"))
{
nIndex = clbReports.FindString(str);
if (nIndex > -1)
{
clbReports.SetItemChecked(nIndex, bSelected);
}
}
}
}
else
{
if (strCheckBox.Contains("Show All Error Reports") || bShowAllIsChecked)
{
foreach (string str in _strReports)
{
nIndex = clbReports.FindString(str);
if (nIndex > -1)
{
clbReports.SetItemChecked(nIndex, false);
}
}
}
nIndex = clbReports.FindString(strCheckBox);
if (nIndex > -1)
{
clbReports.SetItemChecked(nIndex, bShowAllIsChecked ? true : bSelected);
}
}
string[] strCheckedItems = new string[clbReports.CheckedItems.Count];
clbReports.CheckedItems.CopyTo(strCheckedItems, 0);
List<string> checkBoxReportFilter = new List<string>();
foreach (ReportRecord obj in this._lstReportRecords)
{
foreach (string str in strCheckedItems)
{
if (str.Contains(obj.Description))
{
checkBoxReportFilter.Add(obj.PartID.ToString());
}
}
}
try
{
if (checkBoxReportFilter.Count == 0 && clbReports.CheckedItems.Count > 0)
{
throw new NullReferenceException();
}
_strReportFilter = String.Join(",", checkBoxReportFilter.ToArray());
}
catch (NullReferenceException)
{
_strReportFilter = "-1";
}
generateReport();
}
And here is the code where I am clearing the items, getting the report counts and creating the new items.
_lstReportRecords = _dataController.ReportList;
bool[] bChecked = new bool[clbReports.Items.Count];
int nCounter = 0;
foreach (string str in _strReports)
{
foreach (string str2 in clbReports.SelectedItems)
{
bChecked[nCounter] = str2.Contains(str);
}
nCounter++;
}
clbReports.Items.Clear();
nCounter = 0;
foreach (string str in _strReports)
{
int nCount = _lstReportRecords.Where<ReportRecord>(delegate(ReportRecord rr) {
return rr.Description == str;
}).Count();
string newReport = str + " (" + nCount + ")";
clbReports.Items.Add(newReport);
clbReports.SetItemChecked(nCounter, bChecked[nCounter]);
nCounter++;
}
Please tell me there is an easier way to do this. I tried doing foreach loops through the clbReports.Items but it wants me to cast it to a string (errored on me when trying to cast to a CheckBox) so I couldn't change the value. And even if I could cast it to a CheckBox, I have a feeling it will give me the error that Enumeration has failed because the list has been changed (or however they word it). Any and all help is welcome. Thanks.
Edit: Please know that the Report X are just so that the actual report names aren't displayed to keep it generic. However, in the code, I just copied and pasted so the Show All Error Reports and Show All Tagged Records are reports I need to check.
The right ( == most simple and most direct) answer and solution is:
this.clbReports.Items[nIndex] = "new text of the item"
yes, those items are of type "object". No, nobody minds that, string is an object too ;)
If I were you, I'd try to give the INotifyPropertyChanged Interface a go.
You Shouldn't mess with events unless necessary. this will mean you can't use the designer to create the items, but as far as I've understood, it's a runtime-modified list anyway...
In detail:
• Create A Class (e.g.'Foo') that Implements INotifyPropertyChanged (Basically this will tell any listener that the text property has changed). This class will hold the names of all entries.
• create an ObservableCollection and bind your CheckedListBox to that Collection. In WinForms you will have to create a DataBindingSource and plug your Collection to one end and the ComboBox to the other end.
• Any change made to the collection will be visible in the control.
HTH
Sebi
In order to change the items in a ListBox (or a CheckedListBox), you should change these items' ToString() result.
The easiest solution would be to create a "Holder" class, which has a reference to the report it represents. Then the Holder class' ToString() method should be something like this:
public override string ToString()
{
return String.Format("{0} ({1})", BaseStr, MyReport.RecordCount);
}
If you change MyReport.RecordCount somehow (because a report's record count changes), you can just call clbReports.Refresh(), and it'll automatically show the new value.
I think this way you don't even need the temporary array solution in the second code block; however, I'd like to suggest an alternative way of getting the item's checked state.
You can iterate through the clbReports.CheckedIndices, and fill your bChecked array with true values only for indices in that array.
Well, due to time constraints I tried something else. I went with a ListView where CheckBoxes = true and View = List. I also removed Show All Error Reports and Show Tagged Records to checkboxes outside of the list. This made it a lot easier to do the functions I wanted. Here is the new code.
MainForm.Designer.cs
//
// cbTaggedRecords
//
this.cbTaggedRecords.AutoSize = true;
this.cbTaggedRecords.Location = new System.Drawing.Point(151, 9);
this.cbTaggedRecords.Name = "cbTaggedRecords";
this.cbTaggedRecords.Size = new System.Drawing.Size(106, 17);
this.cbTaggedRecords.TabIndex = 3;
this.cbTaggedRecords.Text = "Tagged Records";
this.cbTaggedRecords.UseVisualStyleBackColor = true;
this.cbTaggedRecords.CheckedChanged += new System.EventHandler(this.ShowTaggedRecords_CheckChanged);
//
// cbAllErrorReports
//
this.cbAllErrorReports.AutoSize = true;
this.cbAllErrorReports.Location = new System.Drawing.Point(6, 9);
this.cbAllErrorReports.Name = "cbAllErrorReports";
this.cbAllErrorReports.Size = new System.Drawing.Size(102, 17);
this.cbAllErrorReports.TabIndex = 2;
this.cbAllErrorReports.Text = "All Error Reports";
this.cbAllErrorReports.UseVisualStyleBackColor = true;
this.cbAllErrorReports.CheckedChanged += new System.EventHandler(this.ShowAllErrorReports_CheckChanged);
//
// listView1
//
this.listView1.CheckBoxes = true;
listViewItem1.StateImageIndex = 0;
listViewItem2.StateImageIndex = 0;
listViewItem3.StateImageIndex = 0;
listViewItem4.StateImageIndex = 0;
listViewItem5.StateImageIndex = 0;
listViewItem6.StateImageIndex = 0;
listViewItem7.StateImageIndex = 0;
listViewItem8.StateImageIndex = 0;
listViewItem9.StateImageIndex = 0;
this.listView1.Items.AddRange(new System.Windows.Forms.ListViewItem[] {
listViewItem1,
listViewItem2,
listViewItem3,
listViewItem4,
listViewItem5,
listViewItem6,
listViewItem7,
listViewItem8,
listViewItem9});
this.listView1.Location = new System.Drawing.Point(6, 29);
this.listView1.Name = "listView1";
this.listView1.Size = new System.Drawing.Size(281, 295);
this.listView1.TabIndex = 1;
this.listView1.UseCompatibleStateImageBehavior = false;
this.listView1.View = System.Windows.Forms.View.List;
this.listView1.ItemChecked += new System.Windows.Forms.ItemCheckedEventHandler(this.listView_ItemChecked);
MainForm.cs
private void listView_ItemChecked(object sender, ItemCheckedEventArgs e)
{
if (e != null)
{
int nLength = e.Item.Text.IndexOf("(") - 1;
string strReport = nLength <= 0 ? e.Item.Text : e.Item.Text.Substring(0, nLength);
if (e.Item.Checked)
{
_lstReportFilter.Add(strReport);
}
else
{
_lstReportFilter.Remove(strReport);
}
}
List<string> checkBoxReportFilter = new List<string>();
foreach (ReportRecord obj in this._lstReportRecords)
{
foreach (string str in _lstReportFilter)
{
if (str.ToLower().Contains(obj.Description.ToLower()))
{
checkBoxReportFilter.Add(obj.PartID.ToString());
}
}
}
try
{
if (checkBoxReportFilter.Count == 0 && listView1.CheckedItems.Count > 0)
{
throw new NullReferenceException();
}
_strReportFilter = String.Join(",", checkBoxReportFilter.ToArray());
}
catch (NullReferenceException)
{
_strReportFilter = "-1";
}
if (!bShowAll)
{
generateReport();
}
}
private void ShowAllErrorReports_CheckChanged(object sender, EventArgs e)
{
bShowAll = true;
foreach (ListViewItem lvi in listView1.Items)
{
lvi.Checked = ((CheckBox)sender).Checked;
}
_lstReportFilter.Clear();
bShowAll = false;
generateReport();
}
private void ShowTaggedRecords_CheckChanged(object sender, EventArgs e)
{
bool bChecked = ((CheckBox)sender).Checked;
if (bChecked)
{
if (!_lstReportFilter.Contains("Show Tagged Records"))
{
_lstReportFilter.Add("Show Tagged Records");
}
}
else
{
_lstReportFilter.Remove("Show Tagged Records");
}
listView_ItemChecked(null, null);
}
Code to add counts to CheckBoxes
_lstReportRecords = _dataController.ReportList;
int nTotalCount = 0;
foreach (ListViewItem lvi in listView1.Items)
{
int nCount = _lstReportRecords.Where(rr => lvi.Text.Contains(rr.Description)).Count();
nTotalCount += nCount;
lvi.Text = (lvi.Text.Contains("(") ? lvi.Text.Substring(0, lvi.Text.IndexOf("(") + 1) : lvi.Text + " (") + nCount.ToString() + ")";
}
cbAllErrorReports.Text = (cbAllErrorReports.Text.Contains("(") ? cbAllErrorReports.Text.Substring(0, cbAllErrorReports.Text.IndexOf("(") + 1) : cbAllErrorReports.Text + " (") + nTotalCount.ToString() + ")";
int nTaggedCount = _lstReportRecords.Where(rr => rr.Description.Contains("Tagged")).Count();
cbTaggedRecords.Text = (cbTaggedRecords.Text.Contains("(") ? cbTaggedRecords.Text.Substring(0, cbTaggedRecords.Text.IndexOf("(") + 1) : cbTaggedRecords.Text + " (") + nTaggedCount.ToString() + ")";
Thank you all for your help and ideas.