tags:

views:

649

answers:

3

How can I bind the count of a list to a label. The following code does't get updated with the list is changed:

private IList<string> list = new List<string>();
//...
label1.DataBindings.Add("Text", list.Count, "");
+1  A: 

Bindings listen to the PropertyChanged event of the IPropertyChanged interface. I don't think that List.Count is reported as a PropertyChanged event when it is changed.

What you could do is to implement your custom List or to find a collection that notifies when the Count is changed.

Sergiu Damian
I think that the BindingList class will fire events when it changes, so that might work better.
Andy
A: 

You can use DataSourceChanged if you have a datasource for the listbox. Just remember to update and rebind the datasource.

This may be a bit ghetto but here is the example I worked with:

List<int> collection = new List<int>();
    public Form1()
    {
        InitializeComponent();
        listBox1.DataSourceChanged += listbox1_Changed;
    }

    private void button1_Click(object sender, EventArgs e)
    {
        collection.Add(new Random().Next(100));
        listBox1.BeginUpdate();
        listBox1.DataSource = null;
        listBox1.DataSource = collection;
        listBox1.EndUpdate();
    }
    private void listbox1_Changed(object sender, EventArgs e)
    {
        textBox1.Text = collection.Count.ToString();
    }
+1  A: 

According to Marc Gravell for this problem, he has suggested to create a facade that wraps the collection you want to bind to label1.Text

I have tried to implement one (for fun) and was able to get binding to Count working.
CountList<T> is a facade that wraps a collection to bind to.

Here is the full of the demo.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;

namespace TextBindingTest
{
    public partial class Form1 : Form
    {
        private readonly CountList<string> _List =
            new CountList<string>(new List<string> { "a", "b", "c" });

        public Form1()
        {
            InitializeComponent();
            BindAll();
        }

        private void BindAll()
        {
            var binding = new Binding("Text", _List, "Count", true);
            binding.Format += (sender, e) => e.Value = string.Format("{0} items", e.Value);
            label1.DataBindings.Add(binding);
        }

        private void addToList_Click(object sender, EventArgs e)
        {
            _List.Add("a");
        }

        private void closeButton_Click(object sender, EventArgs e)
        {
            Close();
        }
    }

    public class CountList<T> : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged = delegate { };
        private void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            var handler = PropertyChanged;
            handler(this, e);
        }

        private ICollection<T> List { get; set; }
        public int Count { get { return List.Count; } }

        public CountList(ICollection<T> list)
        {
            List = list;
        }

        public void Add(T item)
        {
            List.Add(item);
            OnPropertyChanged(new PropertyChangedEventArgs("Count"));
        }
    }
}
Sung Meister
I think this does the job, but boy is it complicated! You'd think there should be easier ways of doing simple bindings like this. Seems to me all data binding functionality in Winforms is to cater for lists and grids.
Khash
Yes, it does look more complicated than it needs to be. I have started looking into WPF lately, and this kind of annoyng binding issue seems resolved in XAML
Sung Meister
Sounds about right ;-p
Marc Gravell