我有一个自定义的WinForms控件,其中包含一个ListView,该ListView必须从CSV文件中读取多达20000个项目。
我使用CSVHelper在单独的线程中加载文件,然后调用
listView1.Add
在UI线程上添加它们
ListView
.
我目前的实现(如您在代码中看到的)可能很糟糕,因此在将这20000个项目添加到
ListView
.
请注意,我对线程安全和多线程开发相当陌生。
这是我的自定义控件的整个代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Globalization;
using CsvHelper;
using System.IO;
using System.Threading;
namespace MyDevTaskDesktop
{
public partial class MyCSVReaderControl : UserControl
{
List<Product> loadedProducts;
public MyCSVReaderControl()
{
InitializeComponent();
}
private void BtnBrowse_Click(object sender, EventArgs e)
{
CsvFileDialog.ShowDialog();
}
private void CsvFileDialog_FileOk(object sender, CancelEventArgs e)
{
TxtFilename.Text = CsvFileDialog.FileName;
listView1.Items.Clear();
listView1.Visible = false;
listView1.View = View.Details;
listView1.AllowColumnReorder = true;
listView1.GridLines = true;
listView1.Sorting = SortOrder.Ascending;
listView1.FullRowSelect = true;
listView1.AllowColumnReorder = true;
listView1.Columns.Add("#", 50, HorizontalAlignment.Left);
listView1.Columns.Add("Filename", 100, HorizontalAlignment.Left);
listView1.Columns.Add("Id", 100, HorizontalAlignment.Left);
listView1.Columns.Add("Quantity", 50, HorizontalAlignment.Right);
listView1.Columns.Add("Price", 50, HorizontalAlignment.Right);
LoadCSVThread();
loadedProducts = new List<Product>();
}
public void LoadCSV()
{
using (var reader = new StreamReader(CsvFileDialog.FileName))
using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
{
csv.Configuration.HasHeaderRecord = false;
csv.Configuration.IgnoreBlankLines = true;
csv.Configuration.BadDataFound = null;
csv.Configuration.AutoMap<CsvProduct>();
csv.Configuration.Delimiter = ";";
var records = csv.GetRecords<CsvProduct>().ToList();
int index = 0;
string firstFilename = null;
Color foreColor;
foreach (CsvProduct product in records)
{
index++;
if (firstFilename == null)
{
firstFilename = product.Filename;
}
foreColor = (firstFilename == product.Filename) ? Color.Red : Color.Blue;
loadedProducts.Add(new Product()
{
Color = foreColor,
Index = index,
Filename = product.Filename,
Id = product.Id,
Quantity = product.Quantity,
Price = product.Price
});
if (LblProcess.InvokeRequired)
{
LblProcess.Invoke((MethodInvoker)delegate ()
{
LblProcess.Text = "Processed " + index + " records...";
});
}
}
if (LblProcess.InvokeRequired)
{
LblProcess.Invoke((MethodInvoker)delegate ()
{
LblProcess.Text = "Finished!";
LblProcess.Visible = false;
});
}
if (listView1.InvokeRequired)
{
listView1.Invoke((MethodInvoker)delegate ()
{
listView1.Visible = true;
listView1.BeginUpdate();
foreach (var item in loadedProducts)
{
ListViewItem listItem = new ListViewItem(new string[]
{
item.Index.ToString(),
item.Filename,
item.Id,
item.Quantity.ToString(),
item.Price.ToString()
});
listItem.ForeColor = item.Color;
listView1.Items.Add(listItem);
//listView1.EnsureVisible(listView1.Items.Count - 1);
}
listView1.Sort();
listView1.EndUpdate();
});
}
}
}
public void LoadCSVThread()
{
Thread worker = new Thread(LoadCSV);
worker.IsBackground = true;
worker.SetApartmentState(ApartmentState.STA);
worker.Start();
}
private class Product
{
public Color Color { get; set; }
public int Index { get; set; }
public string Filename { get; set; }
public string Id { get; set; }
public int Quantity { get; set; }
public double Price { get; set; }
}
private class CsvProduct
{
public string Filename { get; set; }
public string Id { get; set; }
public int Quantity { get; set; }
public double Price { get; set; }
}
}
}
我也试过
async/await
,但最终由于我尚不清楚的原因而变得更慢。当我使用这些时,UI中的任何内容在迭代数组时都没有更新。
我知道我的方法来填补
loadedProducts
List
首先迭代该列表以更新视图是不好的,但目前这会产生最快的结果——这是我能做的最好的事情,因为如果我在更新的同时更新UI
LblProcess
标签文本,它会变慢,加倍。
那么,将20000个或更多项目添加到
ListView
?