Datagridview仅显示最后一条记录问题及指定数据展示需求
Root Cause of the Bug
You're almost certainly overwriting the DataGridView's DataSource on every iteration of your for loop's else branch, instead of collecting all matching records first and then binding them once.
For example, if your code looks something like this (the broken version):
// ❌ BROKEN CODE - overwrites DataSource every time foreach (var item in excelData) { var invoiceMatch = GetInvoiceRecord(item.UnitCode); if (item.CurrentReading >= invoiceMatch.CurrentReading) { // Do something for non-matching cases } else { // This replaces the DataSource with only this single record dataGridView1.DataSource = new List<InvoiceRecord> { invoiceMatch }; } }
Each time you hit the else branch, you're replacing the entire DataGridView source with just that one record—so only the last iteration's record stays visible.
Fixed Solution
The fix is simple: collect all matching records in a collection first, then bind that collection to the DataGridView once after the loop finishes. Here's a complete, working example:
Step 1: Define a Model (Optional but Recommended)
First, create a strong-typed class to represent your Invoice records (you can use a DataTable instead if you prefer):
public class InvoiceRecord { public int Serial { get; set; } public int UnitCode { get; set; } public int CurrentReading { get; set; } public int Year { get; set; } public int Month { get; set; } }
Step 2: Updated btn_import Click Event
private void btn_import_Click(object sender, EventArgs e) { // 1. Load your Excel data (replace with your actual Excel reading logic) List<(int UnitCode, int CurrentReading)> excelRecords = new List<(int, int)> { (12, 2000), (14, 4500) }; // 2. Load Invoice data from SQL Server (replace with your actual query logic) // Example using a list - in real code, use ADO.NET or EF to pull from SQL Server 2012 List<InvoiceRecord> invoiceRecords = new List<InvoiceRecord> { new InvoiceRecord { Serial = 1, UnitCode = 12, CurrentReading = 1000, Year = 2018, Month = 3 }, new InvoiceRecord { Serial = 3, UnitCode = 14, CurrentReading = 5000, Year = 2018, Month = 3 } }; // 3. Collect ALL matching records (Excel CurrentReading < Invoice CurrentReading) List<InvoiceRecord> matchingRecords = new List<InvoiceRecord>(); foreach (var excelItem in excelRecords) { // Find the matching Invoice record for this unitcode var invoiceMatch = invoiceRecords.FirstOrDefault(inv => inv.UnitCode == excelItem.UnitCode); if (invoiceMatch != null && excelItem.CurrentReading < invoiceMatch.CurrentReading) { // Add the matching record to our collection matchingRecords.Add(invoiceMatch); } } // 4. Bind the full collection to DataGridView ONCE dataGridView1.DataSource = matchingRecords; // Optional: Auto-resize columns for better readability dataGridView1.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells); }
Alternative: Use LINQ for a More Concise Solution
If you prefer, you can use LINQ to filter the matching records in one line instead of a foreach loop:
private void btn_import_Click(object sender, EventArgs e) { // Load Excel and Invoice data as before // Use LINQ to join and filter records var matchingRecords = from excel in excelRecords join invoice in invoiceRecords on excel.UnitCode equals invoice.UnitCode where excel.CurrentReading < invoice.CurrentReading select invoice; // Bind to DataGridView dataGridView1.DataSource = matchingRecords.ToList(); dataGridView1.AutoResizeColumns(); }
Key Takeaway
The critical mistake was overwriting the DataGridView's data source during each loop iteration. By collecting all valid records first and then binding once, you ensure all matching records (in this case, the unitcode 14 entry) are displayed correctly.
内容的提问来源于stack exchange,提问作者ahmedaziz1985

