Why listbox and datagridview does not update ?

Kimberley 30 Reputation points
2023-02-01T08:23:24.24+00:00

Hi,

I am relatively new to C# and am learning WindowsFormApp at the moment. My questions are related to listbox and datagridview please.

  1. Why does Datagridview rely on the get Property of the related class to display the items, while listbox uses a list ? i.e., why is there the need for this difference ? Also, with Datagridview, I noticed that if the get Property returns a list, such get Property does not even get displayed as an item in the Datagridview. Only get Properties that return "simpler" types like int/double/string etc show up. Why is this the case ?
  2. I know that BindingList class can be used to bind a list to a listbox and datagridview, e.g., via setting the DataSource of a listbox and datagridview. The difference between a BindingList and List being that BindingList allows a list to be "binded" to the listbox and/or datagridview so that changes made to the list can be automatically updated.
    However, I find that in some occasions, the changes in the list are not displayed. Even when I've implemented codes that make logical sense. So when are the situations in which the displays will recognize the update, and when will they not ? And for those situations which will not update automatically, do I just need to use Refresh at each time? On a separate note, I read also that I would need to make use of the interface INotifyPropertyChanged. And that the reason I had issues, was because I didn't use this interface. But why is there a need for a INotifyPropertyChanged, on top of a BindingList, when the whole purpose of BindingList was to "bind" the data, hence, automatically update the related changes in the listbox/datagridview ?
    Is this some kind of a bug/ something missed out in C# when the BindingList was introduced ?

Thank you for your time in advance.

C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
10,309 questions
0 comments No comments
{count} vote

Accepted answer
  1. Reza Aghaei 4,936 Reputation points MVP
    2023-02-01T20:55:21.9233333+00:00

    Here are the things that I can share about your questions:

    Databinding in DataGridView vs ListBox

    Both DataGridView and ListBox are expected to show a list of data items. But DataGridView have multiple columns, while ListBox is a single list of data. Imagine a List<Person>; you can show it in ListBox, but you need to determine which property of the Person should be displayed in the ListBox, otherwise what you can see in the list, will be what is returned by Person.ToString() which is usually the type name, unless you override and return a meaningful string. When you bind the same List<Person> to DataGridView, if you haven't setup DataGridView to show specific columns, it automatically shows all the properties, and for each property, it shows the string representation of the property. For example if there's a Children property which is a List<Person> again, then you will see the string representation of it which is typically the type name. But both controls provide good mechanism for displaying data properly, including CellFormatting event of DataGridView, or many other mechanisms. For example, you can take a look at Show Properties of a Navigation Property in DataGridView (Second Level Properties).

    So here are the highlights for your first question:

    • Always the string representations of the properties will be used for them, no matter if the property is a simple type (int, string, bool) or a complex type (Person, Product), or a list (like List<Person>, Produc[]) which follows the same rule as complex types. It's ToString() method of the type which will be used to display it.
    • If you want to change the string representation, you need to override the ToString() method, or use the features of the control. For example, in ListBox, you can determine what property should be used to show data in the list, using DisplayMember, or you can use Format event to format the data to display. Same applies to DataGridView, where you can determine what properties to display, or use CellFormatting event to format display data. Or for both controls you can format data before using in data binding, just for example using a Linq query.
    • Both controls can show a list of data which is an IList, IBindingList, ITypedList, etc. For IEnumerable, you need to use a BindingSource (yes, different from BindingList).

    BindingList, INotifyPropertyChanges an seeing the updates

    In Windows Forms, in a scenario that you want to see changes of data source in the bound list control, like ComboBox, ListBox or DataGridView (complex two-way data binding), you should use a class that implements IBindingList interface as DataSource of data binding. The most suitable implementation is BindingList<T>. This way each add/remove in the underlying data source of your control will be visible in the control immediately.

    Please keep in mind, using BindingList<T> allows the bound control see added or removed items, but to see also property changes immediately, T should implement INotifyPropertyChanged. This way your your controls will be notified of PropertyChanged and always show fresh data.

    DataTable is the only data structure ready to use which has implemented both IBindingList and INotifyPropertyChanged. For more information, take a look at my post here: Databinding to List - See changes of data source in ListBox, ComboBox

    As a highlight for your second question:

    • In two-way databinding, if you want to see changes of the properties, INotifyPropertyChanges in neccesary. The name tells the story; it notifies the changes in properties and this is how the BinsingList can raise ListChanged event for properties as well; otherwise it only raises the event when an item is added or removed.
    • BindingList, basically raises ListChanged event, which helps the UI control to consume the event and show the changes immediately in the control. As I mentioned in previous bullet point, creation, removal events are automatically there, because the BindingList owns the items and knows when it's added or removed so it knows when to raise the ListChanged in case of add or remove. But for modifications, it's properties of the items which are changed, and they are responsible to notify the binding list about the change, and then the BindingList raises the ListChanged event for property modifications as well.

    So, no bug; all expected and documented well.

    More information:

    Take a look at following resources:

    1 person found this answer helpful.

1 additional answer

Sort by: Most helpful
  1. Karen Payne MVP 35,196 Reputation points
    2023-02-01T11:03:18.06+00:00
    1. Unsure where you are getting the get property from.
    2. In regards to a ListBox List, there is a DataSource property too.

    Okay, here is how one should use a DataGridView when binding to a List<T>

    Setup a class/model with INotifyPropertyChanged for change notification when changes are made outside of the DataGridView.

    Example

    public class Contact : INotifyPropertyChanged
    {
        private string _firstName;
        private string _lastName;
        private string _phone;
        private string _email;
        private DateTime _birthDate;
        public int Id { get; set; }
    
        public string FirstName
        {
            get => _firstName;
            set
            {
                _firstName = value;
                OnPropertyChanged();
            }
        }
    
        public string LastName
        {
            get => _lastName;
            set
            {
                _lastName = value;
                OnPropertyChanged();
            }
        }
    
        public string Phone
        {
            get => _phone;
            set
            {
                _phone = value;
                OnPropertyChanged();
            }
        }
    
        public string Email
        {
            get => _email;
            set
            {
                _email = value;
                OnPropertyChanged();
            }
        }
    
        public DateTime BirthDate
        {
            get => _birthDate;
            set
            {
                _birthDate = value;
                OnPropertyChanged();
            }
        }
    
        public Contact(int id)
        {
            Id = id;
        }
    
        public Contact()
        {
                
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    

    Then for form code

    1. SortableBindingList allows sorting as the DataGridView does not know how to sort a List<T> but does for a DataTable.
    2. A BindingSource and BindingList (SortableBindingList) provide access to data without ever touching the actual DataGridView.
    public partial class Form1 : Form
    {
    
    	private readonly BindingSource _bindingSource = new ();
    
    	private readonly BindingList<Contact> _bindingList;
    	public Form1()
    	{
    		InitializeComponent();
    
    		_bindingList = new SortableBindingList<Contact>(CreateOperations.Contacts(500));
    
    		_bindingSource.DataSource = _bindingList;
    		dataGridView1.DataSource = _bindingSource;
    	   
    
    	}
    
    	private void UpdateFirstNameTextBox_Click(object sender, EventArgs e)
    	{
    		_bindingList[_bindingSource.Position].FirstName = FirstNameTextBox.Text;
    	}
    }
    

    ...Note if we did not use change notification the code to change FirstName would not be recognized in the DataGridView but the underlying source would have the change and a novice developer would think I must refresh the DataGridView. There is zero reasons when coded properly to refresh a DataGridView.

    Is this some kind of a bug/ something missed out in C# when the BindingList was introduced ? No.

    0 comments No comments