I wish to add a search function to my application, I've seen many examples however, all of the data is added by the programmer. How would I implement a search function where the parameters/values aren't pre-defined. I'm guessing I'd have to create another instance of a List<> as I'm already using one?
public Form1()
{
InitializeComponent();
}
List<Book> books = new List<Book>();
private void Form1_Load(object sender, EventArgs e)
{
}
//Settng Values
public void button1_Click(object sender, EventArgs e)
{
Book b = new Book();
b.Title = textBox1.Text;
b.ISBN = textBox2.Text;
b.Onloan = trueCheckBox.Checked;
listView1.Items.Add(b.Title + ", " + b.ISBN + ", " + b.Onloan);
books.Add(b);
textBox1.Text = null;
textBox2.Text = null;
}
//Method to check if item is aviable or note - boolean type
void avaiable()
{
if (trueCheckBox.Checked = true)
{
bool onloan = true;
}
else
{
bool onloan = false;
}
}
private void button2_Click(object sender, EventArgs e)
{
Remove();
}
//Remove item from both the List & Listview
void Remove()
{
try
{
listView1.Items.Remove(listView1.SelectedItems[0]);
books.RemoveAt(listView1.SelectedItems[0].Index);
}
catch
{
}
}
//Display information within their field when selected an item is selected
private void listView1_SelectedIndexChanged(object sender, EventArgs e)
{
if (listView1.SelectedItems.Count == 0)
{
return;
}
else
{
textBox1.Text = books[listView1.SelectedItems[0].Index].Title;
textBox2.Text = books[listView1.SelectedItems[0].Index].ISBN;
trueCheckBox.Checked = books[listView1.SelectedItems[0].Index].Onloan;
}
}
//Update the values without having to re-add
private void button3_Click(object sender, EventArgs e)
{
if (listView1.SelectedItems.Count == 0)
{
return;
}
else
{
books[listView1.SelectedItems[0].Index].Title = textBox1.Text;
books[listView1.SelectedItems[0].Index].ISBN = textBox2.Text;
books[listView1.SelectedItems[0].Index].Onloan = trueCheckBox.Checked;
listView1.SelectedItems[0].Text = textBox1.Text + ", " + textBox2.Text + ", "+ trueCheckBox.Checked;
}
}
private void searchBox_TextChanged(object sender, EventArgs e)
{
//Here's where I am stuck, I've added a textField and labelled it search box
}
}
//Class - set & get methods
class Book
{
public string isbn;
public string title;
private Boolean onloan;
public Book()
{
this.isbn = isbn;
this.title = title;
}
public string ISBN
{
get { return isbn; }
set { isbn = value; }
}
public string Title
{
get { return title; }
set { title = value; }
}
public Boolean Onloan
{
get { return onloan; }
set { onloan = value; }
}
}
}
Thank you.
EDIT-
Essentially, the search function should allow the user to search for a book using just a substring i.e. "Mars" should return a the book with the title "The Programmer From Mars" < (Just an example). I'm guessing I'd have to use the .Contain method?
Correct, you will need to use the "Contains" method. Note that "Contains" is case sensitive so you would need to cater for that.
So you would have something like:
var textToSearch = searchBox.Text.ToLower();
var foundBooks = books.Where(book => book.Title.ToLower().Contains(textToSearch)).ToList();
Assuming books is the list of books to search from:
List<Book> searchResult = books.Where(b => b.Title.Contains(searchTerm)).ToList();
This would return a list of books where the input string is found in the title.
You can do exact matching with b.Title == searchTerm, and similar with the other properties of Book.
The syntax above is LINQ and can be a little confusing at first, but works very well for things like this.
Edit:
To use this, you'll want using System.Linq;
Since your search seems to be on TextChanged, you'd want to put this code in your searchBox_TextChanged() method:
This gets the textbox the user is typing into:
TextBox searchTerm = sender as TextBox;
And this filters your list of books by the current search:
List<Book> searchResult = books.Where(b => b.Title.Contains(searchTerm.Text)).ToList();
Note as in the other answer you may want to do ToLower() (or upper) to make searches case-insensitive.
All that's left to do now is display the filtered result searchResult back to the user.
Managed to do it, this is my code and it works. If anyone wants to use it for future reference here it is.
private void button4_Click(object sender, EventArgs e)
{
listView1.SelectedItems.Clear();
for (int i = listView1.Items.Count -1; i >= 0; i--)
{
if (listView1.Items[i].ToString().ToLower().Contains(searchBox.Text.ToLower())) {
listView1.Items[i].Selected = true;
}
}
Related
Having some real trouble understanding where I've gone wrong here. I've marked in the code what and where. I am using an XAML interface and do have objects for everything here. The code compiles but the TextBlock will not update with the result from updateVTCShortCode Thanks for the help!
MAIN PROGRAM
namespace VTCPT
{
/// <summary>
///
/// </summary>
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
public void shortFormCodec_SelectionChanged(object sender, RoutedEventArgs e)
{
//UPDATE THE SHORTCODE TEXTBLOCK
updateVTCShortCode display = new updateVTCShortCode();
display.mergeShortCode(longFormCodec.SelectedItem.ToString());
if (String.IsNullOrEmpty(display.finalResult()))
{ shortFormCodec.Text = ".."; }
else { shortFormCodec.Text = display.finalResult();
shortFormCodec.Text = "test";
} /////THIS IS NOT ACTUALLY GETTING A RETURN
}
public void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
}
private void updateShortForm(object sender, SelectionChangedEventArgs e)
{
}
private void TextBlock_SelectionChanged(object sender, RoutedEventArgs e)
{
}
private void fsSiteBuild_SelectionChanged(object sender, RoutedEventArgs e)
{
}
private void updateSiteBuild(object sender, TextChangedEventArgs e)
{
int index = fsRoomDesig.Text.IndexOf(".");
if (index > 0)
{ fsSiteBuild.Text = fsRoomDesig.Text.Substring(0, index); }
else { fsSiteBuild.Text = ".."; }
}
private void vtcSystemName_SelectionChanged(object sender, RoutedEventArgs e)
{
}
}
}
updateVTCShortCode CLASS
namespace VTCPT
{
class updateVTCShortCode
{
String result = "";
public void mergeShortCode(String longFormCodec)
{ if (longFormCodec.Equals("Cisco SX80"))
{
String sendShortForm = "SX80";
result = "V-T" + sendShortForm;
}
if (longFormCodec.Equals("Cisco Webex Codec Plus"))
{
String sendShortForm = "SRK";
result = "V-T" + sendShortForm;
}
if (longFormCodec.Equals("Cisco Webex Codec Pro"))
{
String sendShortForm = "SRK";
result = "V-T" + sendShortForm;
}
}
public String finalResult()
{ return result; } //////SHOULD BE GETTING SENT BACK TO MAIN PROGRAM
}
}
I think the problem is that in the following code taken from your shortFormCodec_SelectionChanged method. You set shortFormCodec.Text = display.finalResult(); immediately followed by shortFormCodec.Text = "test";. The final result will never be visible because it is being immediately overwritten with "test".
if (String.IsNullOrEmpty(display.finalResult()))
{
shortFormCodec.Text = "..";
}
else
{
shortFormCodec.Text = display.finalResult();
shortFormCodec.Text = "test";
}
As TheGeneral suggested in the comments, you should be able to identify this using breakpoints and stepping through the code (using the F8 key) while watching the values of your variables and text fields. If you hover your mouse over the variables and the .Text section of any shortFormCodec.Text line it will show you its value at that point in the program.
However, I think you may find it helpful if you adjust your code to use an if {} else if {} else {} structure. I would also change the finalResult() method to a property as it's doing nothing but return a string. For example:
class updateVTCShortCode
{
// You could set the default value to an empty string I.e. = ""
// but having it set to "Not set" may help you spot any problems for now.
// As long as you remember to call mergeShortCode() first, you would never
// see "Not set" returned anyway. But this would help you spot that mistake.
public string FinalResult { get; set; } = "Not set";
public void mergeShortCode(String longFormCodec)
{
if (longFormCodec.Equals("Cisco SX80"))
{
String sendShortForm = "SX80";
FinalResult = "V-T" + sendShortForm;
}
else if (longFormCodec.Equals("Cisco Webex Codec Plus"))
{
String sendShortForm = "SRK";
FinalResult = "V-T" + sendShortForm;
}
else if (longFormCodec.Equals("Cisco Webex Codec Pro"))
{
String sendShortForm = "SRK";
FinalResult = "V-T" + sendShortForm;
} else
{
// If longFormCodec is not matched, set the result to ".."
FinalResult = "..";
}
}
By setting the final result to ".." in the else block of the mergeShortCode() method and setting a default value for the FinalResult property (even if it is an empty string I.e. ""). You are preventing FinalResult ever being null and providing all possible outcomes from the one function. This means you can simplify the shortFormCodec_SelectionChanged() method to the following and easily reuse the mergeShortCode() method elsewhere:
public void shortFormCodec_SelectionChanged(object sender, RoutedEventArgs e)
{
//UPDATE THE SHORTCODE TEXTBLOCK
updateVTCShortCode display = new updateVTCShortCode();
display.mergeShortCode(longFormCodec.SelectedItem.ToString());
shortFormCodec.Text = display.FinalResult;
}
}
I am currently creating a winform program where account holders are able to purchase specific products/services.
The current problem I am having is that when I select an account holders name on the combobox, all the account holders details is supposed to be shown on the multiline textbox, however all im getting so far is the account holders name.
Here is the relevant code...
public Form1()
{
InitializeComponent();
mAccHolder[0] = new Customer("Rich", "Bronze Account", 11);
mAccHolder[1] = new Customer("Patrick", "Silver Account", 21);
mAccHolder[2] = new Customer("Steve", "Gold Account", 12);
mAccHolder[3] = new Customer("Kevin", "Platinum Account", 25);
foreach(Customer r in mAccHolder)
{
comboBox1.Items.Add(r.GetName());
}
}
and the code which connects the combobox and textbox together...
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (comboBox1.SelectedIndex == -1)
{
cstTxtBox.Text = string.Empty;
}
else
{
cstTxtBox.Text = comboBox1.SelectedItem.ToString();
}
You are only getting the account holders name because that is all you are giving the combobox. It does not know anything about a Customer. It only knows that it was supplied a string value, and that is all. You can pass it the name, this is fine, but you need to print the information corresponding with what that combobox item represent. You can do this by using an index. Since we know they are being supplied in the combobox in order, the index's will match. However, unless you override the ToString, you are just going to get the object name, e.g. "Customer.Object[]".
I threw an example together for you.
private Customer[] customers = new Customer[3];
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
customers[0] = new Customer("Bob", "Bronze", 22);
customers[1] = new Customer("Jane", "Silver", 32);
customers[2] = new Customer("Jordan", "Gold", 26);
foreach(var cust in customers)
{
comboBox1.Items.Add(cust.Name);
}
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
textBox1.Text = customers[comboBox1.SelectedIndex].ToString();
}
Also, in your 'Customer' class you may want to override the "ToString()" to make this nicer.
public override string ToString()
{
return Name + "\r\n" + Membership + "\r\n" + Age;
}
Using your example with an array of “Customer” objects, when the combo box's selected value changes, you need to get the selected “Customer” Object from the array mAccHolder. Once you have this customer either you can output the “Customer” values individually to the text box or you could make a “ToString” method for the “Customer” to output the customer info to your specifications, which is what the code below does.
The changes below to your current code appear to work as described. I added a blank value to the combo box so the user can de-select any currently selected customer. The “GetCustomer” method simply loops through the array mAccHolder to get the selected customer in the combo box. Hope this helps.
Customer Class
class Customer {
public string Name { get; set; }
public string AccountType { get; set; }
public int ID { get; set; }
public Customer(string inName, string actType, int inID) {
Name = inName;
AccountType = actType;
ID = inID;
}
public string GetName() {
return Name;
}
public override string ToString() {
return "Name: " + Name + " AccountType: " + AccountType + " ID: " + ID;
}
}
Updated code to use the Customer Class above.
Customer[] mAccHolder = new Customer[10];
public Form1() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
mAccHolder[0] = new Customer("Rich", "Bronze Account", 11);
mAccHolder[1] = new Customer("Patrick", "Silver Account", 21);
mAccHolder[2] = new Customer("Steve", "Gold Account", 12);
mAccHolder[3] = new Customer("Kevin", "Platinum Account", 25);
comboBox1.Items.Add(""); // <- add a blank selection so the user can select NO customer
foreach (Customer r in mAccHolder) {
comboBox1.Items.Add(r.GetName());
}
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e) {
if (comboBox1.SelectedIndex == -1) {
cstTxtBox.Text = string.Empty;
} else {
if (comboBox1.SelectedItem.ToString() != "") {
Customer selectedCustomer = GetCustomer(comboBox1.SelectedItem.ToString());
if (selectedCustomer != null)
cstTxtBox.Text = selectedCustomer.ToString();
else
cstTxtBox.Text = "Customer not found!";
}
else {
cstTxtBox.Text = "No Customer selected";
}
}
}
private Customer GetCustomer(string targetName) {
foreach (Customer curCustomer in mAccHolder) {
if (curCustomer.Name.Equals(targetName)) {
return curCustomer;
}
}
return null;
}
Easy add directly Customer to combobox. With this way you can use it anywhere any time. like this.
public Form1()
{
InitializeComponent();
mAccHolder[0] = new Customer("Rich", "Bronze Account", 11);
mAccHolder[1] = new Customer("Patrick", "Silver Account", 21);
mAccHolder[2] = new Customer("Steve", "Gold Account", 12);
mAccHolder[3] = new Customer("Kevin", "Platinum Account", 25);
foreach(Customer r in mAccHolder)
{
ComboboxItem item = new ComboboxItem();
item.Text = r.GetName();
item.Value = r;
comboBox1.Items.Add(item);
}
}
And use Customer where you want...
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (comboBox1.SelectedIndex == -1)
{
cstTxtBox.Text = string.Empty;
}
else
{
Customer c=(Customer) comboBox1.SelectedValue;
cstTxtBox.Text = c.whatyouwant....
}
You can use foreach,
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (comboBox1.SelectedIndex == -1)
{
cstTxtBox.Text = string.Empty;
}
else
{
foreach (var item in comboBox1.Items)
{
cstTxtBox.Text = cstTxtBox.Text + item.ToString();
}
}
}
I have this short windows form application code that i cannot get to work properly. It uses an instance of a class (as a temporary storage place) to populate an array of the same class type. It has a button and a textbox. If you press the button, the text is saved in the Name member and added to the array.
If the Name is taken by another array member, it should show a message "name taken!" and not add it to the array. The problem is that this condition check is always true!
if we type in "Marry", the debugger shows that
if (examleArray[i].Name == temp.Name)
is equivalent to:
if ("Marry" == "Marry")
as if one is pointing to the other. Why is this? how do i fix it? thank you!
namespace errorexample
{
public partial class Form1 : Form
{
example temp = new example();
example[] examleArray = new example[10];
int examleArrayIndex = 0;
bool NameTaken = false;
public Form1()
{ InitializeComponent(); }
private void button1_Click(object sender, EventArgs e)
{
temp.Name = textBox1.Text;
NameTaken = false;
for (var i = 0; i < (examleArrayIndex); i++)
{
if (examleArray[i].Name == temp.Name)
{
NameTaken = true;
MessageBox.Show("Name taken!");
}
}
if (NameTaken == false)
{
examleArray[examleArrayIndex] = temp;
examleArrayIndex++;
}
}
}
public class example {
public string Name;
}
}
You only have one temp object, and you add keep adding it to the array. It's the same temp since you never create a new one. I've rewritten it for you:
List<example> examleArray = new List<example>();
private void button1_Click(object sender, EventArgs e)
{
if (examleArray.Any(e=>e.Name == textBox1.Text))
{
MessageBox.Show("Name taken!");
} else {
examleArray.Add(new example { Name = textBox1.Text });
}
}
I've also converted your fixed array into a List so you don't ever accidentally try and add 11 names and then blow up. And I've converted your search to LINQ to simplify.
You only create one example object. You are putting multiple references to the same object into the array. One solution is to create a new example object to put in the array:
public class example {
public string Name;
public example( string name ){
Name = name;
}
}
//...
examleArray[examleArrayIndex] = new example( temp.Name );
move temp object initialization inside the click event, otherwise you are updating same object
private void button1_Click(object sender, EventArgs e)
{
example temp = new example();
temp.Name = textBox1.Text;
NameTaken = false;
for (var i = 0; i < (examleArrayIndex); i++)
{
if (examleArray[i].Name == temp.Name)
{
NameTaken = true;
MessageBox.Show("Name taken!");
}
}
if (NameTaken == false)
{
examleArray[examleArrayIndex] = temp;
examleArrayIndex++;
}
}
you can use List
List<string> example =
new List<string>();
if(example.Contains(textBox1.Text))
{
MessageBox.Show("Name taken!");
}else
{
example.Add(textBox1.Text);
}
I'm using Entity Framework to throw together a combobox with values from my MSSQL database using the following
using (var context = new Entity())
{
var things = (from p in context.Stuff
where ((p.SourceId == StuffId && p.Domain.Value == "Stuff")
|| (p.SourceId == OtherStuffId && p.Domain.Value == "OtherStuff"))
&& p.Done == true orderby p.StuffId
select p);
foreach(var stuff in things)
cboRejectTask.Items.Add(stuff.StuffId + ": " + stuff.StuffType.Description + " " + stuff.StuffType.DisplayName);
}
I'd like to assign values to each row so that when it comes time to grab what the user selected I don't have to do string manipulation to get what I want. I don't want to use a datasource if possible.
Solution:
Given there isn't a better way to do this than creating a custom class I went ahead and did so using the selected answer's code modified a bit for long-term use. (note: you could really use any given object as long as ToString() returned the "display text" and it had a Tag or any writeable property compatible with your needs)
public class ComboBoxItem
{
public string Display;
public object Value;
public override string ToString()
{
return Display;
}
}
Given this code I can now change my code to the following:
using (var context = new Entity())
{
var things = (from p in context.Stuff
where ((p.SourceId == StuffId && p.Domain.Value == "Stuff")
|| (p.SourceId == OtherStuffId && p.Domain.Value == "OtherStuff"))
&& p.Done == true orderby p.StuffId
select p);
foreach(var stuff in things)
cboRejectTask.Items.Add(new ComboBoxItem() { Display = stuff.StuffId + ": " + stuff.StuffType.Description + " " + stuff.StuffType.DisplayName, Value = stuff.StuffId });
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
var cbi1 = new ComboBoxItem("Item 1") { Id = 1 };
var cbi2 = new ComboBoxItem("Item 2") { Id = 2 };
var cbi3 = new ComboBoxItem("Item 3") { Id = 3 };
comboBox1.Items.Add(cbi1);
comboBox1.Items.Add(cbi2);
comboBox1.Items.Add(cbi3);
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
var id = ((ComboBoxItem)comboBox1.SelectedItem).Id;
MessageBox.Show(id.ToString());
}
}
public class ComboBoxItem
{
private readonly string text;
public int Id { get; set; }
public ComboBoxItem(string text)
{
this.text = text;
}
public override string ToString()
{
return text;
}
}
I think you might find this usefull:
comboBox1.Items.Add(1);
comboBox1.Items.Add(2);
comboBox1.Items.Add(3);
private void comboBox1_Format(object sender, ListControlConvertEventArgs e)
{
//this will set what gets displayed in the combobox, but does not change the value.
e.Value = "display value";
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
MessageBox.Show((sender as ComboBox).SelectedItem.ToString());
}
this probably will be confusing or messy but I need help with my program
this is my program:
public partial class Form1 : Form
{
int itemCountInteger;
public struct Patient
{
public string patientidstring;
public string firstNameString;
public string lastNameString;
}
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
public class Patientn
{
private int patientId;
public string firstName;
private string lastName;
public Patientn()
{
patientId = 0;
firstName = "";
lastName = "";
}
public Patientn(int idValue, string firstNameVal, string lastNameVal)
{
patientId = idValue;
firstName = firstNameVal;
lastName = lastNameVal;
}
}
I want to be able to use a patient class instead of a struct to add patients and for the search code bellow I get the error "operators == cannot be applied" i want to be able to search the array if the text in textbox matches a name in array if so display surname help?
//Array
Patient[] patientInfo = new Patient[10];
private void button1_Click(object sender, EventArgs e)
{
try
{
foreach (Patient patientinfoIndex in patientInfo)
patientInfo[itemCountInteger].patientidstring = textBox1.Text;
patientInfo[itemCountInteger].firstNameString = textBox2.Text;
patientInfo[itemCountInteger].lastNameString = textBox3.Text;
string names = patientInfo[itemCountInteger].firstNameString + " " + patientInfo[itemCountInteger].lastNameString;
listBox1.Items.Add(names);
itemCountInteger++;
listBox1.SelectedItem = names;
}
catch
{
MessageBox.Show("Contacts are limited to 20. Please delete some contacts prior to adding more.");
}
}
//Search Button search a patients name and display his surname in the label if patient is found display his surname
private void button2_Click(object sender, EventArgs e)
{
int intTest = 0;
for (int x = 0; x < patientInfo.Length; x++)
{
if (textBox4.Text == patientInfo[x])
{
label6.Text =("surname");
intTest = 1;
}
}
if (intTest == 0)
{
label6.Text = ("not found");
}
}
I'm new to all of this sorry for asking and thanks in advance if you can help me with anything.
You're getting the error because of this line; textBox4.Text == patientInfo[x]. There are a few problems here but firstly, textBox4.Text is a string and you're trying to do an equality comparison with a Patient the compiler is saying there is no == operator defined for that. You can overload the == operator for Patient but this would only allow you to compare one instance of type Patient to another, never will you be able to compare a Patient to a string unless you cast both to type object in which case it's just going to do a reference comparison (not what you want).
I'm not sure which property in Patient you want to use here but I do know you need to compare textBox4.Text to one of the strings within the Patient class. Something like this would work; (textBox4.Text == patientInfo[x].lastName)
It makes no sense to compare System.String--the type returned by textBox4.Text--to a Patientn instance. You probably mean to compare Text to patientInfo[x].lastNameString.
You can't do
textBox4.Text == patientInfo[x]
patientInfo contains instances of Patience and textBox4.Textis a string. There is no possible comparison between those two and that's why you get the error.
You're probably trying to do something like this
textBox4.Text == patientInfo[x].patientidstring