Search code examples
c#winformschecklistbox

Save a user's clicks in checkListBox


In my app, I have a few of checkListBoxes and I need to save clicks on this list. That means for the next time I don't need to click on them again and again.

Code:

public Form2()
{
    InitializeComponent();
    InitializeSecondForm();
}

private void InitializeSecondForm()
{
    this.Height = Properties.Settings.Default.SecondFormHeight;
    this.Width = Properties.Settings.Default.SecondFormWidth;
    this.Location = Properties.Settings.Default.SecondFormLocation;

    this.FormClosing += SecondFormClosingEventHandler;
    this.StartPosition = FormStartPosition.Manual;
}

private void SecondFormClosingEventHandler(object sender, FormClosingEventArgs e)
{
    Properties.Settings.Default.SecondFormHeight = this.Height;
    Properties.Settings.Default.SecondFormWidth = this.Width;
    Properties.Settings.Default.SecondFormLocation = this.Location;

    Properties.Settings.Default.Save();
}

I tried to use this question for my answer, but it's not working: Save CheckedListBox Items to Settings

With a simple checkBox it's not a problem, but here we have a list.

Any idea how to do it?


Solution

  • Perhaps saving identifiers of each checked item to a json file.

    In the following I did on CheckedListBox, for multiple CheckedListBox controls you need to adjust the code to use one json file with a modified structure to account for multiple CheckedListBox control or one json file per CheckedListBox.

    Example, load items into the following class

    public class Product
    {
        public int ProductID { get; set; }
        public string ProductName { get; set; }
        public override string ToString()
        {
            return ProductName;
        }
    
    }
    

    Use the following class for read/write to a json file, in this case using json.net but will work also with system.text.json.

    public class JsonOperations
    {
        /// <summary>
        /// In your app you need to setup a different file name for each CheckedListBox
        /// </summary>
        public static string FileName => 
            Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Checked.json");
    
        /// <summary>
        /// Save only checked products
        /// </summary>
        /// <param name="list"></param>
        public static void Save(List<ProductItem> list)
        {
            string json = JsonConvert.SerializeObject(list, Formatting.Indented);
            File.WriteAllText(FileName, json);
        }
    
        /// <summary>
        /// Read back if file exists
        /// </summary>
        /// <returns></returns>
        public static List<ProductItem> Read()
        {
            List<ProductItem> list = new List<ProductItem>();
    
            if (File.Exists(FileName))
            {
                list = JsonConvert.DeserializeObject<List<ProductItem>>(File.ReadAllText(FileName));
            }
    
            return list;
        }
    }
    

    The following classes provide methods to get checked items set checked items from json mentioned above.

    public static class CheckedListBoxExtensions
    {
        public static List<ProductItem> IndexList(this CheckedListBox sender)
        {
            return
            (
                from item in sender.Items.Cast<Product>()
                    .Select(
                        (data, index) =>
                            new ProductItem()
                            {
                                ProductID = data.ProductID,
                                Index = index
                            }
                    )
                    .Where((x) => sender.GetItemChecked(x.Index))
                select item
            ).ToList();
        }
        public static void SetChecked(this CheckedListBox sender, int identifier, bool checkedState = true)
        {
            var result = sender.Items.Cast<Product>()
                .Select((item, index) => new CheckItem
                {
                    Product = item, 
                    Index = index
                })
                .FirstOrDefault(@this => @this.Product.ProductID == identifier);
    
            if (result != null)
            {
                sender.SetItemChecked(result.Index, checkedState);
            }
        }
    }
    

    public class CheckItem { public Product Product { get; set; } public int Index { get; set; } }

    Form code would resemble the following to read checked items on form shown event and save checked item on form closing event.

    public partial class SaveItemsForm : Form
    {
        private List<Product> _products = new List<Product>();
        public SaveItemsForm()
        {
            InitializeComponent();
            Shown += OnShown;
            Closing += OnClosing;
        }
    
        private void OnClosing(object sender, CancelEventArgs e)
        {
            List<ProductItem> checkedItems = ProductCheckedListBox.IndexList();
            if (checkedItems.Count > 0)
            {
                JsonOperations.Save(checkedItems);
            }
            else
            {
                JsonOperations.Save(new List<ProductItem>());
            }
        }
    
        private void OnShown(object sender, EventArgs e)
        {
            _products = SqlServerOperations.ProductsByCategoryIdentifier(1);
    
            ProductCheckedListBox.DataSource = _products;
    
            /*
             * Search for each product by id, if in the CheckedListBox check it
             */
            var items = JsonOperations.Read();
            if (items.Count >0 )
            {
                items.ForEach( x => ProductCheckedListBox.SetChecked(x.ProductID));
            }
        }
    }