Resolved Help Exporting and Importing CSV

ceobros

Member
Joined
Jul 8, 2022
Messages
10
Programming Experience
Beginner
I need a way to open a csv file and write the contents of it into a listview component.
I tried but it doesn't work.

Here is my export from listview to csv:

Export to CSV:
        private async void savCoord_Click(object sender, EventArgs e)
        {

            SaveFileDialog saveFileDialog = new SaveFileDialog();
            saveFileDialog.InitialDirectory = Path.GetPathRoot(Environment.SystemDirectory);
            saveFileDialog.Filter = "CSV|*.csv";

            if (saveFileDialog.ShowDialog() == DialogResult.OK)
            {
                using (StreamWriter sw = new StreamWriter(new FileStream(saveFileDialog.FileName, FileMode.Create), Encoding.UTF8))
                using (FileStream fileStream = new FileStream(saveFileDialog.FileName, FileMode.Create))
                using (StreamWriter streamWriter = new StreamWriter(fileStream))
                {
                    foreach (ListViewItem item in PositionsListView.Items)
                    {
                        await sw.WriteLineAsync(string.Format("{0},{1},{2},{3}", item.SubItems[0].Text, item.SubItems[1].Text, item.SubItems[2].Text, item.SubItems[3].Text));
                        MessageBox.Show("Success!", "Notice", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    }
                }

            }
        }

And here is my Import Code (can't figure out how to get it to work)

Import from csv to Listview:
        private void openCoord_Click(object sender, EventArgs e)
        {

            OpenFileDialog openFileDialog = new OpenFileDialog();
            openFileDialog.InitialDirectory = Path.GetPathRoot(Environment.SystemDirectory);
            openFileDialog.Filter = "CSV|*.csv";

            try
            {
                if (openFileDialog.ShowDialog() == DialogResult.OK)
                {
                    FileStream srcFS;
                    srcFS = new FileStream(openFileDialog.FileName, FileMode.Open);
                    StreamReader srcSR = new StreamReader(srcFS, System.Text.Encoding.Default);
                    foreach (ListViewItem item in PositionsListView.Items)
                    {
                        string ins = srcSR.ReadLine();
                        string[] row = { "X", "Y", "L/R", };
                        ListViewItem listViewItem = new ListViewItem(row);
                        PositionsListView.Items.Add(listViewItem);


                    }
                    
                    }
            }
            catch (Exception errorMsg)
            {
                MessageBox.Show(errorMsg.Message, "Error reading a file", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

        }
 
You're not reading the words I'm posting. The specific comment in my code that I directed you to was this:
C#:
// Use fields here.
Here's the code that you just wrote:
C#:
ListViewItem item = new ListViewItem(line.ToString());

item.SubItems.Add($"{item.SubItems[0]},{item.SubItems[1]},{ item.SubItems[2]},{ item.SubItems[3]}");
Where in that code are you using fields? You're not, so you're not doing what I said to do, so why would you expect it to work?

Think about what you're doing. You have a string array containing four elements in the fields variable. You want to create a ListViewItem with those four values. How do you do that? Have you done any research on that? Have you read the documentation I mentioned earlier than contains a relevant code example?

I understand that you're relatively new to this but logic doesn't go out the window because you're new. If you are provided with instructions, follow those instructions. If there's something specific you don't understand, ask about that specifically. Don't just throw stuff at the wall and hope for the best. Don't do something unless there is a logical reason for doing it. Think your way through the steps required first, as though you had to do it manually, then write to implement those steps specifically. If you don't know what the code is supposed to do - that means the steps to get to a result, not just the result itself - then of course you won't be able to write the code to do it.
I seriously have no damn clue, literally no clue, I've looked at the documentation for literally hours and find no correlation to the problem I am having at all, There doesnt seem to even be a way to use fields either. I'm completely lost
 
Think about the steps:
  1. Get the field values from the current line of the file.
  2. Create a ListViewItem containing the field values from 1.
  3. Add the ListViewItem from 2 to the ListView.
You've already got 1 from my code:
C#:
var fields = line.Split(',');
You're creating a ListViewItem here:
C#:
ListViewItem item = new ListViewItem(line.ToString());
but you're not using those field values to populate it. The documentation I directed you to contains this:
C#:
ListViewItem item1 = new ListViewItem("item1",0);
// Place a check mark next to the item.
item1.Checked = true;
item1.SubItems.Add("1");
item1.SubItems.Add("2");
item1.SubItems.Add("3");
so that shows you how to create a ListViewItem, set the Text or the item itself and then add three more subitems. Does that sound a little like what you want to do? You just have to substitute the text values that you already have for the values they use in the example. If you made the effort to use the documentation then you would know that the constructor they are using takes an index for the image but there's another constructor that takes just the text for those not using images. You're also not using check boxes:
C#:
var item = new ListViewItem(fields[0]);

item.SubItems.Add(fields[1]);
item.SubItems.Add(fields[2]);
item.SubItems.Add(fields[3]);
If you made just a little more effort then you'd know that there's another constructor that takes a string array, which fields is:
C#:
var item = new ListViewItem(fields);
Now all that remains is to add the ListViewItem you just created to the ListView:
C#:
PositionsListView.Items.Add(item);
That's following some simple logic and using the information that you already have at your fingertips. Follow instructions when they're provided. Read the relevant documentation. Think about the logic required first and write code to implement that logic specifically. It takes some practice but you need to make sure that you're practicing the right things. This process will become second nature in time.

Now, while that will achieve your aim, it does have an issue. Adding items to a ListView one by one like that is slow, because the control redraws after each item. That's not too big a deal if the number of items is small but performance can be horrendous for large numbers of items. There are two ways to address this issue; one is good and the other better.

The good way is to call BeginUpdate on the control before you start adding items and EndUpdate after you finish. That will prevent the control redrawing between adding items. The better way is to add all the items to a List<ListViewItem> first, then add them all to the ListView in a batch with a call to AddRange:
C#:
var items = new List<ListViewItem>();

foreach (var line in File.ReadLines(filePath))
{
    items.Add(new ListViewItem(line.Split(',')));
}

PositionsListView.Items.AddRange(items.ToArray());
 
Think about the steps:
  1. Get the field values from the current line of the file.
  2. Create a ListViewItem containing the field values from 1.
  3. Add the ListViewItem from 2 to the ListView.
You've already got 1 from my code:
C#:
var fields = line.Split(',');
You're creating a ListViewItem here:
C#:
ListViewItem item = new ListViewItem(line.ToString());
but you're not using those field values to populate it. The documentation I directed you to contains this:
C#:
ListViewItem item1 = new ListViewItem("item1",0);
// Place a check mark next to the item.
item1.Checked = true;
item1.SubItems.Add("1");
item1.SubItems.Add("2");
item1.SubItems.Add("3");
so that shows you how to create a ListViewItem, set the Text or the item itself and then add three more subitems. Does that sound a little like what you want to do? You just have to substitute the text values that you already have for the values they use in the example. If you made the effort to use the documentation then you would know that the constructor they are using takes an index for the image but there's another constructor that takes just the text for those not using images. You're also not using check boxes:
C#:
var item = new ListViewItem(fields[0]);

item.SubItems.Add(fields[1]);
item.SubItems.Add(fields[2]);
item.SubItems.Add(fields[3]);
If you made just a little more effort then you'd know that there's another constructor that takes a string array, which fields is:
C#:
var item = new ListViewItem(fields);
Now all that remains is to add the ListViewItem you just created to the ListView:
C#:
PositionsListView.Items.Add(item);
That's following some simple logic and using the information that you already have at your fingertips. Follow instructions when they're provided. Read the relevant documentation. Think about the logic required first and write code to implement that logic specifically. It takes some practice but you need to make sure that you're practicing the right things. This process will become second nature in time.

Now, while that will achieve your aim, it does have an issue. Adding items to a ListView one by one like that is slow, because the control redraws after each item. That's not too big a deal if the number of items is small but performance can be horrendous for large numbers of items. There are two ways to address this issue; one is good and the other better.

The good way is to call BeginUpdate on the control before you start adding items and EndUpdate after you finish. That will prevent the control redrawing between adding items. The better way is to add all the items to a List<ListViewItem> first, then add them all to the ListView in a batch with a call to AddRange:
C#:
var items = new List<ListViewItem>();

foreach (var line in File.ReadLines(filePath))
{
    items.Add(new ListViewItem(line.Split(',')));
}

PositionsListView.Items.AddRange(items.ToArray());

My dumbass was overthinking of how I was supposed to do it. My apologies if this problem made you frustrated towards me. Thank You for your help
 
My dumbass was overthinking of how I was supposed to do it.
Not uncommon. That's why I try to focus people on the logic rather than the code. The tendency can be to think about all the code constructs you know and what you can do to use them to get the result you want. That's really the reverse of what you should do. Think about the logic first, break it down into the smallest steps you can and then tackle each step individually, think about the best code construct to perform that step specifically. Each step should be so basic that it takes about three lines of code max, and often just one. If your logic is sound then implementing all the steps correctly will inherently produce the expected result. If it doesn't. you can then step through the code in debugger and examine every step to see which one doesn't do as expected. If they all do as expected and you still don't get the expected result then it's your logic that is at fault. Fear not for this is the process I went through when I started out too.
 
Just something to keep in mind when parsing csv files. Windows assumes that csv files should be opened by Excel. So users will simply double click a csv file and it opens with Excel. After they mess around with the spreadsheet and exit they MAY save the file. Excel will insert commas allover the place to make the file balanced in rows and columns. Watch you parsing for these phantom commas.

Replacing quotes in strings before parsing will make life much more simple. Read the entire file into a single string, use String.Replace(), split on \r\n or commas, whichever the case, all done.
 
Back
Top Bottom