我尝试搜索列表框,但它只搜索第一列,其他列好像不存在。列表框中的数据由空格分隔,它是 4 列数据。
这是我尝试过的
listBox1.ClearSelected();
string data = txtSearch.Text;
if (!string.IsNullOrEmpty(data))
{
int index = listBox1.FindString(data);
if (index >= 0)
{
listBox1.SetSelected(index, false);
MessageBox.Show("string" + data + "found at index " + index);
txtSearch.Clear();
}
else
{
MessageBox.Show("Search string did not match any item");
txtSearch.Clear();
}
}
您忘记写下如何填写列表框。通常有两种方法来填充列表框:
您没有说明您要显示什么类型的内容,让我们假设您显示产品的一些属性:Id、Name、Price。您希望将它们显示在列表框中整齐的列中。
class Product
{
public int Id {get; set;}
public string Name {get; set;}
public decimal Price {get; set;}
... // other properties
}
某个地方有一个方法可以获取要在列表框中显示的产品:
IEnumerable<Product> GetProductsToDisplay() {...}
每当您想在 winforms 控件中显示项目序列时,这是首选方法,因为使用此方法,您不会在显示的产品描述中思考,而是在
DisplayedProduct
的对象中思考。如果操作员在列表框中选择一个字符串,则他在内部选择了一个产品。软件更容易确定选择哪个产品。
除了更容易访问产品之外,使用数据源还可以将显示的项目与用于显示它的控件分离。如果稍后您决定要在 DataGridView 中显示产品序列,则更改很小。如果您想在更奇特的控件(如图表)中显示产品(的价格),您甚至可以重用这些类。
class DisplayedProduct
{
// ths format string to convert the Product into its displayformat
private const string descriptionFormat = ...;
public Product Product {get; set;}
public string Description => String.Format(descriptionFormat,
this.Product.Id,
this.Product.Name,
this.Product.Price);
}
在表单的构造函数中,您使用属性 ListControl.DisplayMember 来定义用于显示的属性:
void MyForm()
{
InitializeComponent();
this.myListbox.DisplayMember = nameof(DisplayedProduct.Description);
}
您也可以使用 Visual Studio Designer 来执行此操作,但此方法的优点是,如果出现输入错误,编译器会抱怨。
现在展示产品:
IEnumerable<Product> DisplayedProducts
{
get => this.myListBox.DataSource
.Select(displayedProduct => displayedProduct.Product);
set => this.myListBox.DataSource = value
.Select(product => new DisplayedProduct {Product = product))
.ToList();
}
因此,要显示您的产品,您需要提供一系列产品,set 属性会将其转换为
list<DisplayedProducts>
,并将结果放入 ListBox 的数据源中。
要获取 DisplayedProducts,需要从数据源中获取
list<DisplayedProducts>
。从该列表中的每个元素中,获取属性 Product。
展示您的产品只需一行:
this.DisplayedProducts = this.GetProductsToDisplay();
创建方法 DisplayedProducts 后,可以轻松搜索名称中包含特定文本的产品:
const string textToSearch = "Hammer"
// find all Hammers:
IEnumerable<Product> hammers = this.DisplayedProducts
.Where(product.Name.Contains(textToSearch);
// find the most expensive Hammer
Product mostExpensiveHammer = this.DisplayedProducts
.Where(product.Name.Contains(textToSearch)
.OrderByDescending(product => product.Price)
.FirstOrDefault();
我认为使用数据源可以轻松回答您的问题。
因为您将产品与其显示方式分离,所以很容易
所以我的建议是使用数据源在列表框中显示产品
为了完整起见,以下属性可能会很方便:
Product SelectedProduct => (DisplayedProduct)(this.SelectedValue)?.Product;
如果您使用 ListBox.Items 来显示产品,您的表单将具有如下方法:
// Formats the product into ListBox description, using columns
string ProductToListBoxDescription(Product product)
{
const string listBoxProductDescriptionFormat = ...;
return String.Format(listBoxProductDescriptionFormat,
product.Id,
product.Name,
product.Price);
}
void DisplayProductDescriptions(IEnumerable<string> products)
{
this.myListBox.Items.Clear;
foreach (Product product in Pro
this.myListBox.Items.AddRange(products.ToArray());
}
要获取显示的产品:
IEnumerable<string> DisplayedProductDescriptions => this.myListBox.Items.Cast<string>();
这个缺点是,您丢失了获取的字符串是产品的信息。当然,您可以假设字符串包含产品:
const string textToSearch= "Hammer"
string foundHammer = this.DisplayedProductDescriptions
.Where(description => discription.Contains(textToSearch))
.FirstOrDefault();
首先,你的结果仍然是一个字符串。其次,如果您尝试搜索“2.0”,例如尝试查找版本号为 2.0 的所有产品,该怎么办?您还会发现价格为 €2.0 和 €42.0 等的产品说明。
因此,为了正确使用,您需要一种将字符串转换回产品的方法
Product DescriptionToProduct(string productDescription)
{
... // TODO implement. Depends on the columns in your listBox
}
除了如果使用属性 Items 显示的产品描述比使用属性 DataSource 时大得多之外,此方法还会删除列表框中显示的项目是产品的信息,这需要额外的代码将字符串转换回来到产品。
所以我的建议是:虽然属性 Items 有效,但坚持使用属性 DataSource。