0

I am trying to make a winform application. The app has 2 textboxes (firstName, lastName), a numericUpDown, and a checkbox. The app is able to read from a text file, with comma separated rows (Daniel,Brown,26,true). The app put this info in a listbox. Then you can add a new user. When you are finished adding users you press save and the new info from lisbox will be saved in that text file. I've created the read file script and add user succesfully. However I can't create the save user button so that it'll save: Daniel,Brown,26,true. I was able to save as: Daniel,Brown,26,happy. Here is the Person Class:

public class Person
{        
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Age { get; set; }
    public bool IsHappy { get; set; }

    public override string ToString()
    {
        var statusText = IsHappy ? "happy" : "not happy";
        return $"{FirstName} {LastName} is {Age} and is {statusText}";
    }   
}

Here is the form.cs with it's script:

public partial class ChallengeForm : Form
{
    private BindingList<Person> _persons = new BindingList<Person>();
    private PersonsService _personsService;

    public ChallengeForm()
    {
        _personsService = new PersonsService();
        InitializeComponent();
        WireUpDropDown();            
    }

    private void WireUpDropDown()
    {
        _persons = new BindingList<Person>(_personsService.GetPersons(@"C:\Users\user\Desktop\Document.TXT"));
        usersListBox.DataSource = _persons;
    }

    private void addUserButton_Click(object sender, EventArgs e)
    {
        var person = new Person { FirstName = firstNameText.Text, LastName = lastNameText.Text, Age = agePicker.Text, IsHappy = isHappyCheckbox.Checked };
        _persons.Add(person);
    }

    private void saveListButton_Click(object sender, EventArgs e)
    {
    }
}

My question is how can I convert the status back to bool. And write the listbox to the text file as csv. I would be very thankfull if you could use SoC. Here is what I've tried:

const string sPath = (@"C:\Users\user\Desktop\Document.TXT");

        System.IO.StreamWriter SaveFile = new System.IO.StreamWriter(sPath);
        SaveFile.Write(myperson);
        foreach (var item in usersListBox.Items)
        {

            List<string> unwantedWords = new List<string> { "is", "and" };
            var linesSplitted = item.ToString().Split(' ').ToList();
            var wordsWithoutUnwantedWords = linesSplitted.Where(i => !unwantedWords.Contains(i)).ToList();
            for (int i = 0; i<wordsWithoutUnwantedWords.Count; i++)
            {
                var isLastWord = i == wordsWithoutUnwantedWords.Count - 1;

            SaveFile.Write(wordsWithoutUnwantedWords[i]);

                if (!isLastWord)
                {
                    SaveFile.Write(",");
                }
Kaiser
  • 606
  • 8
  • 22
  • `write the listbox to the text file`, please show us what you have tried. Also since you have a list of `Person` that is bound to the control, writing this out is much easier. – Trevor Oct 21 '19 at 19:11
  • Serialize (convert to comma-separated strings, in this case) the `_persons` List (without using the `ToString()` method, of course). Maybe add another public method that returns the properties values already converted to comma-separated strings. Similar to what you're doing in `ToString()`, but CSV-oriented :). Or maybe consider JSON to serialize/deserialize your class objects. – Jimi Oct 21 '19 at 19:11
  • The code you should show is in `PersonsService`. A [mre] would start there, with the code that successfully reads the file and your attempt at writing the file. Side note: this has to be a duplicate of probably over a dozen questions about writing CSV files. It's impossible to know which because we can't see what you've tried. Do some more searching. – madreflection Oct 21 '19 at 19:14
  • Just edited, at the end you can see what I've tried – alexander123 Oct 21 '19 at 19:30
  • The problem is right there: you're using the result of `ToString` as the basis for your CSV output. Use the properties directly. Among other benefits, changes to what `ToString` should return won't cause you to have to change your CSV routines. Better yet, use a proven library like [CSVHelper](https://www.nuget.org/packages/CsvHelper/) instead. – madreflection Oct 22 '19 at 21:19

1 Answers1

0

Look into XML Serialization. You can just pass in your filepath and the object and the rest will be done for you by the Serialisation classes. Code below:

This is taken from DeadlyDog's awesome answer: https://stackoverflow.com/a/22417240/1623971

/// <summary>
/// Writes the given object instance to an XML file.
/// <para>Only Public properties and variables will be written to the file. These can be any type though, even other classes.</para>
/// <para>If there are public properties/variables that you do not want written to the file, decorate them with the [XmlIgnore] attribute.</para>
/// <para>Object type must have a parameterless constructor.</para>
/// </summary>
/// <typeparam name="T">The type of object being written to the file.</typeparam>
/// <param name="filePath">The file path to write the object instance to.</param>
/// <param name="objectToWrite">The object instance to write to the file.</param>
/// <param name="append">If false the file will be overwritten if it already exists. If true the contents will be appended to the file.</param>
public static void WriteToXmlFile<T>(string filePath, T objectToWrite, bool append = false) where T : new()
{
    TextWriter writer = null;
    try
    {
        var serializer = new XmlSerializer(typeof(T));
        writer = new StreamWriter(filePath, append);
        serializer.Serialize(writer, objectToWrite);
    }
    finally
    {
        if (writer != null)
            writer.Close();
    }
}

/// <summary>
/// Reads an object instance from an XML file.
/// <para>Object type must have a parameterless constructor.</para>
/// </summary>
/// <typeparam name="T">The type of object to read from the file.</typeparam>
/// <param name="filePath">The file path to read the object instance from.</param>
/// <returns>Returns a new instance of the object read from the XML file.</returns>
public static T ReadFromXmlFile<T>(string filePath) where T : new()
{
    TextReader reader = null;
    try
    {
        var serializer = new XmlSerializer(typeof(T));
        reader = new StreamReader(filePath);
        return (T)serializer.Deserialize(reader);
    }
    finally
    {
        if (reader != null)
            reader.Close();
    }
}

Sample use case:

WriteToXmlFile<Person>("C:\someClass.txt", objectToSerialize);

// Read the file contents back into a variable.
Person deserializedObject = ReadFromXmlFile<Person>("C:\someClass.txt");
demoncrate
  • 390
  • 2
  • 14