ListBox và ComboBox
Nhân viên cần chọn một sản phẩm trong danh sách để xem giá. Thêm tay từng
dòng vào control thì dài và dễ sai. Bài này đưa cả một List<Product> vào
control để nó tự hiện tên từng sản phẩm.
Khái niệm
📋 ListBox: control hiện một danh sách để người dùng chọn.
🔽 ComboBox: control thu gọn thành một ô, bấm vào mới xổ danh sách xuống để chọn.
🔗 DataSource: property nhận cả một danh sách object để control hiện mỗi object thành một dòng.
DisplayMember là tên property của object được đem ra hiện trên dòng đó.
Ví dụ
Product lấy từ chương EF Core của khoá ASP.NET Core, tạm bỏ Stock cho
gọn. Chương sau mới đọc sản phẩm từ Oracle, bài này tạo sẵn trong bộ nhớ.
class MainForm : Form
{
private readonly List<Product> _products =
new List<Product>
{
new Product
{
Id = 1, Name = "Bút bi", Price = 5000m
},
new Product
{
Id = 2, Name = "Vở", Price = 12000m
}
};
private readonly ListBox _productList =
new ListBox { Width = 250 };
private readonly Label _priceLabel =
new Label { AutoSize = true };
public MainForm()
{
Text = "Sản phẩm";
_productList.DataSource = _products;
_productList.DisplayMember = "Name";
_productList.SelectedIndexChanged +=
ProductList_SelectedIndexChanged;
var panel = new FlowLayoutPanel
{
Dock = DockStyle.Fill,
FlowDirection = FlowDirection.TopDown,
Padding = new Padding(12)
};
panel.Controls.Add(_productList);
panel.Controls.Add(_priceLabel);
Controls.Add(panel);
}
private void ProductList_SelectedIndexChanged(
object? sender, EventArgs e)
{
object? item = _productList.SelectedItem;
if (item == null)
{
return;
}
var product = (Product)item;
_priceLabel.Text = $"Giá: {product.Price}";
}
}
public class Product
{
public int Id { get; set; }
public string Name { get; set; } = "";
public decimal Price { get; set; }
}DataSource = _productsđưa cả danh sách vào.DisplayMember = "Name"cho mỗi dòng hiện tên sản phẩm.SelectedItemcó kiểuobject, vìListBoxchứa được mọi loại object.(Product)itemép nó vềProduct. Khác(int)ở bài Toán tử và ép kiểu, phép ép này không đổi object mà chỉ cho compiler biết object thật làProduct. Sai kiểu thì báoInvalidCastException.SelectedIndexChangedchỉ chạy khi lựa chọn thay đổi. Lúc mở form, dòng đầu được chọn sẵn nhưng event chưa chạy, nên nhãn giá còn trống cho tới khi bạn chọn dòng khác.
ComboBox
ComboBox dùng đúng các property trên. Thêm DropDownStyle để người dùng
chỉ được chọn, không gõ chữ tuỳ ý vào ô:
var productBox = new ComboBox
{
Width = 250,
DropDownStyle = ComboBoxStyle.DropDownList
};Thử ngay
Trong constructor, xoá dòng _productList.DisplayMember = "Name"; rồi chạy
lại.
Đoán trước khi chạy: danh sách hiện gì, tên sản phẩm hay thứ khác?
Xem kết quả
ShopDesk.Product
ShopDesk.ProductThiếu DisplayMember, control gọi ToString() của từng object. Mặc định
ToString() trả về tên đầy đủ của class, gồm cả namespace.
Lỗi hay gặp
Gắn hai control vào cùng một list. Hai control đó dùng chung cả vị trí
đang chọn: chọn "Vở" ở ComboBox thì ListBox cũng nhảy sang "Vở".
// SAI — chọn ở ô này, ô kia nhảy theo
_productList.DataSource = _products;
productBox.DataSource = _products;// ĐÚNG — mỗi control một bản list riêng
_productList.DataSource = _products;
productBox.DataSource =
new List<Product>(_products);Tóm tắt
DataSourcenhận cả danh sách,DisplayMemberchọn property để hiện.SelectedItemlàobject, ép về kiểu thật bằng(Product).- Thiếu
DisplayMemberthì mỗi dòng hiện kết quảToString(). ComboBoxvớiDropDownListchỉ cho chọn, không cho gõ.
Tự kiểm tra
0/3 câuListBox có DataSource là List<Customer>. Muốn mỗi dòng hiện email của khách, đặt gì?
Vì sao phải viết (Product)item trước khi đọc .Price?
ComboBox chọn đơn vị tính chỉ cho chọn trong danh sách, không cho gõ chữ khác. Đặt property nào?