One path (of several) is to create a class which represents your data on the form which implements INotifyPropertyChanged interface. In the form, create a form level scoped BindingList<T> where T is the class representing your data. Couple this with a BindingSource where the BindingList becomes the DataSource of the BindingList and the BindingSource is the DataSource of the ListBox.
Sample class where .ToString becomes the string to show in the ListBox
public class Customer : INotifyPropertyChanged
{
private string _firstName;
private string _lastName;
public int CustomerIdentifier { get; set; }
public string FirstName
{
get => _firstName;
set
{
_firstName = value;
OnPropertyChanged();
}
}
public string LastName
{
get => _lastName;
set
{
_lastName = value;
OnPropertyChanged();
}
}
public override string ToString() => $"{FirstName} {LastName}";
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Form code. Since this was done quickly to show conceptually the moving parts the edit aspect is half-baked but does work
namespace CustomersDemo
{
public partial class ListBoxSaveForm : Form
{
private BindingList<Customer> _customersBindingList;
private readonly BindingSource _customersBindingSource = new();
public ListBoxSaveForm()
{
InitializeComponent();
Shown += OnShown;
}
private void OnShown(object? sender, EventArgs e)
{
_customersBindingList = new BindingList<Customer>();
_customersBindingSource.DataSource = _customersBindingList;
CustomersListBox.DataSource = _customersBindingSource;
}
private void AddButton_Click(object sender, EventArgs e)
{
if (!string.IsNullOrWhiteSpace(FirstNameTextBox.Text) && !string.IsNullOrWhiteSpace(LastNameTextBox.Text))
{
_customersBindingList.Add(new Customer() { FirstName = FirstNameTextBox.Text, LastName = LastNameTextBox.Text });
}
}
private void EditCurrentButton_Click(object sender, EventArgs e)
{
if (_customersBindingSource.Count > 0 && CustomersListBox.SelectedIndex > -1)
{
if (!string.IsNullOrWhiteSpace(FirstNameTextBox.Text) && !string.IsNullOrWhiteSpace(LastNameTextBox.Text))
{
_customersBindingList[CustomersListBox.SelectedIndex].FirstName = FirstNameTextBox.Text;
_customersBindingList[CustomersListBox.SelectedIndex].LastName = LastNameTextBox.Text;
}
}
}
}
}
Edit
Save to Json class
using System;
using System.IO;
using System.Text.Json;
namespace CustomersDemo
{
public static class SystemJson
{
public static (bool result, Exception exception) JsonToFile<T>(this T sender, string fileName, bool format = true)
{
try
{
/*
* explore other options besides WriteIndented
*/
var options = new JsonSerializerOptions
{
WriteIndented = true
};
File.WriteAllText(fileName, JsonSerializer.Serialize(sender, format ? options : null));
return (true, null);
}
catch (Exception exception)
{
return (false, exception);
}
}
}
}
Button click
private void JsonSaveButton_Click(object sender, EventArgs e)
{
if (_customersBindingList.Count <= 0) return;
var (success, exception) = _customersBindingList.JsonToFile("CustomersSaved.json");
MessageBox.Show(exception is null ? "Saved" : $"Failed\n{exception.Message}");
}
Another path is to use a BindingSource with a DataTable.
If you need to save there are a handful of sources e.g. database, text file, xml file, json to name a few.