Sequence contains no match element but Element is there - c#

I have a simple search box and button that is bound to a command, the command fires fine and passes the textbox parameter but when it hits the SearchStock method it runs through the list and doesn't match the parameter even though the element is there? Don't understand why its not matching, possibly my poor LINQ skills
Search Stock method
private void SearchStock(object _ticker)
{
var stock = Stocks.SingleOrDefault(x => x.Ticker == _ticker.ToString());
_selectedstock = (Stock)stock;
}
When I step into it it is showing the element ticker, I noticed that there were spaces after the Ticker name so I changed the column to NVARCHAR but it still didn't work

Ok so you find why it is not working all alone. "FB " is not equal to "FB".
You have 2 options :
Try to fix the used stored database string format.
use var stock = Stocks.SingleOrDefault(x => x.Ticker.Trim() == _ticker.ToString()); to ignore space in code

Related

Add specific values from DataGridView to Listbox (Windows Forms / NET Framework 4.7)

In my DataGridView (DGV1) I have a table with different string values (N1-N9). Some of these cell values are highlighted in yellow (this appears bold in the table (N1, N5, N6)). I want to add these selected cells in a ListBox as shown below.
var foundValues = dataGridView1.Rows.Cast<DataGridViewRow>().Select(row => new
{
Name = row.Cells[row.Cells.Cast<DataGridViewCell>().First(cell => cell.OwningColumn.HeaderText == "XX").ColumnIndex].Value,
ColorValue = row.Cells.Cast<DataGridViewCell>().Where(c => c.Style.BackColor == Color.Yellow).Select(cell => cell.Value.ToString()),
Count = row.Cells.Cast<DataGridViewCell>().Count(c => c.Style.BackColor == Color.Yellow),
}).ToArray();
foreach (var s in foundValues)
{
listBox1.Items.Add($"{s.Name}, {s.ColorValue}, {s.Count}");
}
Unfortunately my output contains an error. The yellow highlighted cell values (strings) are not displayed in the ListBox.
DD1, System.Linq.Enumerable + WhereSelectEnumerableIterator‘2[SystemWindows.Forms.DataGridViewCell,System.String],1
DD2, System.Linq.Enumerable + WhereSelectEnumerableIterator‘2[SystemWindows.Forms.DataGridViewCell,System.String],2
DD3, System.Linq.Enumerable + WhereSelectEnumerableIterator‘2[SystemWindows.Forms.DataGridViewCell,System.String],0
Could anyone please help me? Many thanks in advance!
My LINQ skills are amateur at best, however from the output in the ListBox…
DD1, System.Linq.Enumerable + WhereSelectEnumerableIterator‘2[SystemWindows.Forms.DataGridViewCell,System.String],1
It appears the second value is a “collection.” And this makes sense looking at the ColorValue variable…
ColorValue = row.Cells.Cast<DataGridViewCell>().Where(c => c.Style.BackColor == Color.Yellow).Select(cell => cell.Value.ToString()),
This may return more than ONE value… and each value would be a simple string like.. “N5” and “N6”, but the object is STILL a “collection.” Therefore, when you execute the code…
listBox1.Items.Add($"{s.Name}, {s.ColorValue}, {s.Count}");
And s.ColorValue is a “collection”… the ListBox isn’t smart enough to take that collection and turn it into a “single” comma separated string value.
Therefore, the code needs to do this “combining” of the different string values in the collection. I am guessing there is a way to do this using LINQ, but my feeble attempts failed and I ended up using the String.Join method to combine the strings in the collection.
In my tests, setting the ColorValue variable to the joined strings appears to work as you want.
The change I made is below using your code. This single change displayed the values properly in the ListBox as you have shown. Granted it appears you may need to fudge a little to get the proper comma placement, however this should be trivial.
ColorValue = String.Join(", ", row.Cells.Cast<DataGridViewCell>().Where(c => c.Style.BackColor == Color.Yellow).Select(cell => cell.Value)),
I hope this makes sense and helps.

How to execute advance Listview Search

Using Windows forms, My 'listview' have multiple columns as shown in the picture.
I have been trying to make this txtbox_search to be advanced. When any character, word or number is inserted, i want Some columns of my listview to be traversed to look for the character, word, number and bring up data related to the input.
Like when i enter: txtbox_search.Text = "a"
It should travers column "Name" and fill Listview with data:
entire row that has a name which starts with "a" such as "Anwar"
entire row that has a name which starts with "a" such as "Anas"
so on with entire rows that has a name which starts with "A..."
when i enter: txtbox_search.Text = "1"
It should travers column "ID" and fill Listview with data:
entire row that has a ID which starts with "1" such as "1002"
entire row that has a ID which starts with "1" such as "1112"
so on with entire rows that has a ID which starts with "1..."
so far i have been trying this for 2 days and end up with this much:
private void textBox_DEC_Search_TextChanged(object sender, EventArgs e)
{
foreach(ListViewItem Items in listView_DEC_CustomerList.Items)
{
if(Items.Text == textBox_DEC_Search.Text)
{
listView_DEC_CustomerList.Items.Clear();
listView_DEC_CustomerList.Items.Add(Items);
}
}
if(textBox_DEC_Search.Text == "" || textBox_DEC_Search.Text == string.Empty)
{
CusList Cus = new CusList();
Cus.CustomersList(listView_DEC_CustomerList);
}
}
This code only travers first column and bring up data that matches the inserted ID, only if the Complete ID matches with txtbox_search.Text how can i make this possible? (i want it to be on client side, not from sql/database). Guides and sample code helps will be really appreciated. Thanks.
To distinguish between your 2 criteria you could use the following:
if (textBox_DEC_Search.Text.All(x => Char.IsNumber(x)))
{
Debug.WriteLine("Number");
// search through ID
}
else
{
Debug.WriteLine("Name");
// search through Name
}
It basically checks whether your input is solely numeric.
EDIT:
To check for similarity you cold use String.StartsWith of String.Contains to make the search a little more flexible
to look for the ID or NAME you need to access the subitems!
since ID is your first column check SubItems[0]
if(Items.SubItems[0].Text.StartsWith(textBox_DEC_Search.Text) ||
Items.SubItems[0]Text.Contains(textBox_DEC_Search.Text))
since NAME is your second column check SubItems[1]
if(Items.SubItems[1].Text.StartsWith(textBox_DEC_Search.Text) ||
Items.SubItems[1]Text.Contains(textBox_DEC_Search.Text))
One Problem is this line:
listView_DEC_CustomerList.Items.Clear();
because it will erase the first found result when the second is found.
So if you find 10 matches the previous 9 will be deleted!
I suggest to make first the entire search and then add the results if there are any:
private void textBox_DEC_Search_TextChanged(object sender, EventArgs e)
{
// index is 0 if numeric for ID or 1 if not for NAME
int ind = textBox_DEC_Search.Text.All(x => Char.IsNumber(x)) ? 0 : 1;
List<ListViewItem> matchlist = new List<ListViewItem>();
foreach(ListViewItem Items in listView_DEC_CustomerList.Items)
{
if(Items.SubItems[ind].Text.StartsWith(textBox_DEC_Search.Text) ||
Items.SubItems[ind]Text.Contains(textBox_DEC_Search.Text))
{
matchlist.Add(Items);
}
}
// if you have found something add the all results
if(matchlist.Any())
{
listView_DEC_CustomerList.Items.Clear();
listView_DEC_CustomerList.Items.AddRange(matchlist.ToArray());
}
}
Disclaimer: Although this solution should work I would vote to follow the advice of #RezaAghaei. It is less messy and confusing than directly manipulating the ListView
Instead of using == which looks for an exact match try one of the following (I am assuming 'Text' is the column name in the list containing the name - if not change it to Items.Name (for example)
if you want to search on 'starting with' then try
if (Items.Text.StartsWith(textBox_DEC_Search.Text.Trim())
if you want to search based on the fact that a part of the string should be looked up then try
if (Items.Text.Contains(textBox_DEC_Search.Text.Trim())
You can similarly do for any other column you would like to search on. if you want to make the search case insensitive then use .ToLower() on the string and the column name.

Searching for record in c# Winform (Entity Framework)

I have a c# winform with textboxes, connected via Entity Framework to a table, called Candidates (it has 700 records).
I'm using a BindingSource named candidatesBindingSource. Everything works as I want.
There is just one thing. I'm trying to implement searching candidates with surnames. So i have a Textbox, called textSurname and a Button with this code
for searching through my records:
var searchResults = (from a in _context.Candidates where (a.Surname.Contains(textSurname.Text)) select a.Id).ToList();
if (searchResults.Count > 0)
{
// Id of a record in searchResults is correct
var position = searchResults[0];
// This line moves focus to a wrong record
candidatesBindingSource.Position = position; //
}
If a record is found, I can get its Id. And here I have a problem. How can I reposition my candidatesBindingSource to the
record with the Id from my searchResults? For example, if I have an Id = 2638, the code above repositions my candidatesBindingSource
to the last record. I'm suspecting that this part candidatesBindingSource.Position actualy works as recordcount (700 in my table)
and is unable to go to the record nr. 2638 (not to the record with this Id). Am I right? So how can I implement a GOTO record with my found Id?
Do I really have to use a For loop with MoveNext command to compare my searched Id with all Id's?
Any hint would be very appreciated.
Ok, so this is how you initialize you binding source
candidatesBindingSource.DataSource = _context.Candidates.ToList();
Then you don't need to search the database, you can search the data source list using the List.FindIndex method like this:
var candidateList = (List<Candidate>)candidatesBindingSource.DataSource;
var searchText = textSurname.Text;
var firstMatchIndex = candidateList.FindIndex(c => c.Surname.Contains(searchText));
if (firstMatchIndex >= 0)
candidatesBindingSource.Position = firstMatchIndex;
I think you should set to candidatesBindingSource.Position index of item and not id.
That post will help you to get index of item correctly, witout read whole data again.
Get Row Index in a list by using entity framework
Also you can try get index from your binding source.
If you create a list out of your context it will have the same indexing as the databinding you set on your form. To set your form to look at the result of your search you can use the a match from the FindIndex() method of the list, and then set your .Position to that index.
using (Candidates _context = new Candidates())
{
var candidateList = _context.Candidate.ToList();
var firstCandidateMatchIndex = candidateList.FindIndex(c =>
c.Surname.Contains(textSurname.Text));
if (firstCandidateMatchIndex >= 0)
candidateBindingSource.Position = firstCandidateMatchIndex;
}

Reduce the number of item in datagridview while user types in C#

I have datagrid view filled with values
I have to create a search in datagridview.
private void textBox_Search_TextChanged(object sender, EventArgs e)
{
String search = textBox_Search.Text.Trim();
if (!String.IsNullOrEmpty(search))
{
dataGridView_LicenseKey.SelectionMode = DataGridViewSelectionMode.FullColumnSelect;
webservicelicencesBindingSource.Filter = string.Format("{0}= '{1}'", "nom_centre", search);
}
}
I use above code.
Explaination of above code : When i type first letter in the textbox ;the datagridview becomes empty unless i type the complete string which matches the value in datagridview.
What i want : when i press the letter in the text box , datagridview should reduce .
For example :
values in Datagrid view
1. ABCDE
2. ABEFG
3. erdzf
4. rezfj
5. Agfe
When I type "A" in text box
value in Data grid view
1. ABCDE
2. ABEFG
3. Agfe
When I type "AB" in text box
value in Data grid view
1. ABCDE
2. ABEFG
When I type "ABC" in text box
value in Data grid view
1. ABCDE
and so on.
Need help in this.
Thanks in Advance.
Your filter condition is wrong, it filters exact values only. It should look like this:
webservicelicencesBindingSource.Filter = string.Format("{0} LIKE '{1}%'", "nom_centre", search);
(Doesn't have to be uppercase)
EDIT:
To show all results again, you have to improve condition when the search term is empty, like this:
dataGridView_LicenseKey.SelectionMode = DataGridViewSelectionMode.FullColumnSelect;
if (!String.IsNullOrEmpty(search))
{
webservicelicencesBindingSource.Filter = string.Format("{0}= '{1}'", "nom_centre", search);
}
I suppose that bad filtering that you mentioned in the comment could happen because the event is fired at EVERY text change. So if you have search term 'AB', deleting one character by time, it would first filter by 'A', and then would cancel another filter because the search string was empty. This scenario would give mentioned result.

Can we assign more then one template ID in templateId (like we do in relatedId), while searching with Lucene?

I have Five check boxes
Search All
Template 1
Template 2
Template 3
Template 4
If user selects Search All, then simply we can pass index name and get result, if user selects one of template specific check box, again simply we can do by passing template name, but if any of two templates specific check box(or may be three) are checked, then?
Can we pipe-separate templateIDs?
You may need to change the method in the Advanced Database Crawler to handle the GUIDs of templates passed in. The SearchParam class has a property called TemplateIds which by being plural indicates it should allow more than one. However, if you look into the code, this is how it is used:
templateIds = IdHelper.NormalizeGuid(templateIds);
The NormalizeGuid() method actually only returns a single GUID. So I recommend you alter the ApplyTemplateFilter() method here to return multiple Template GUIDs:
protected void ApplyTemplateFilter(CombinedQuery query, string templateIds, QueryOccurance occurance)
{
if (String.IsNullOrEmpty(templateIds)) return;
templateIds = IdHelper.NormalizeGuid(templateIds);
var fieldQuery = new FieldQuery(BuiltinFields.Template, templateIds);
query.Add(fieldQuery, occurance);
}
So change templateIds = IdHelper.NormalizeGuid(templateIds) to handle multiple GUIDs, perhaps by splitting the input at a | to get each GUID then normalizing each one of those and combining them again via a |.
Further to what Mark said this can be achieved by using below function:
protected void ApplyTemplateFilter(CombinedQuery query, string templateIds)
{
if (String.IsNullOrEmpty(templateIds)) return;
var fieldQuery = new CombinedQuery();
var values = IdHelper.ParseId(templateIds);
foreach (var value in values.Where(ID.IsID))
{
AddFieldValueClause(fieldQuery, BuiltinFields.Template, value, QueryOccurance.Should);
}
query.Add(fieldQuery, QueryOccurance.Must);
}

Categories