Thank you for clarifying how you intend to use the data. We'll continue the approach I recommended earlier but note that we're making some assumptions here:
- Your files aren't too big
- You don't have a lot of files
- You don't want to load the data more than once if possible
If any of these assumptions are not true then you'll need to adjust the architecture but this might be a good start. Firstly you will have a type to represent the data in a row. You seem to already have that but I'm calling my version MeasurementRecord
.
public class MeasurementRecord
{
public int SampleNo { get; set; }
public int UdpTime { get; set; }
public int RPM { get; set; }
}
This is what the grid will show. Next we'll have a wrapper class MeasurementFile
that represents the collection of records from a file. It is important that your UI just focus on UI stuff so anything related to how you read/write the data should be elsewhere and we're using this type for that. Later if you need to expand to other sources then this type might be the base class that you start with. For now we'll just use a CSV file though.
public class MeasurementFile
{
public MeasurementFile ( string filePath )
{
FilePath = filePath;
FileName = Path.GetFileName(filePath);
_items = new Lazy<List<MeasurementRecord>>(LoadData);
}
public string FilePath { get; }
public string FileName { get; }
public IEnumerable<MeasurementRecord> GetMeasurements () => _items.Value;
private List<MeasurementRecord> LoadData ()
{
...
}
private readonly Lazy<List<MeasurementRecord>> _items;
}
Finally we have the UI. The UI is just responsible for displaying data and reacting to user input. When the button is clicked we get a directory from the user, create a MeasurementFile
instance for each csv file and bind that to the combo box. When the user selects an item from the combo we get the associated file information and render it in the grid. This allows us to read the data files only once.
private void button1_Click ( object sender, EventArgs e )
{
var dlg = new FolderBrowserDialog();
if (dlg.ShowDialog() != DialogResult.OK)
return;
//Get the CSV files in the directory
//create an instance of each file so we can use it later
var files = Directory.EnumerateFiles(dlg.SelectedPath, "*.csv", SearchOption.AllDirectories)
.Select(x => new MeasurementFile(x))
.ToList();
//Update the combo box with the available files
comboBox1.DisplayMember = nameof(MeasurementFile.FileName);
comboBox1.DataSource = files;
}
private void comboBox1_SelectedIndexChanged ( object sender, EventArgs e )
{
var file = comboBox1.SelectedItem as MeasurementFile;
if (file == null)
{
//Clear out any data
dataGridView1.DataSource = null;
return;
};
//Bind the current file data to the grid
dataGridView1.DataSource = file.GetMeasurements();
}
Now the UI should be working but we need to read the CSV. There are many CSV libraries available but they depend upon your CSV file format. Let's assume your CSV format is the same across files and the header names are consistent as well. We just need to map each line to the corresponding data. I'm using CsvHelper
here but most CSV libraries work the same way. I'm doing a simple mapping here but you can get as complex as you need to.
private List<MeasurementRecord> LoadData ()
{
//Load the data from the CSV and force to List so it only runs once
return LoadDataCore().ToList();
}
private IEnumerable<MeasurementRecord> LoadDataCore ()
{
using (var stream = new StreamReader(FilePath))
using (var reader = new CsvReader(stream, System.Globalization.CultureInfo.InvariantCulture)) {
reader.Read();
reader.ReadHeader();
//Doing this by hand but you could also use the map feature...
while (reader.Read())
{
yield return new MeasurementRecord() {
SampleNo = reader.GetField<int>("SampleNo"),
UdpTime = reader.GetField<int>("UdpTime"),
RPM = reader.GetField<int>("RPM")
};
};
};
}
The above code hides the details of reading a CSV and can be as simple or complex as you need. More importantly the class manages the lifetime of the readers so the UI doesn't have to. For performance reasons it grabs the data only when first requested and returns the same data from that point on. If you need to support editing of the file then this may no longer be a good option but for your OP this should meet the needs.