Search code examples
c#winformsentity-frameworkdatagridviewbindingsource

BindingSource.BindingReset not working


I have the bound my DataGridView to BindingSource but when I call ResetBinding() the DataGridView doesn't get updated to show only those records which have WhenDeleted column value as null:

public partial class LabourSetup : DisplayControl
{
    private List<LABOUR> labourCollection = new List<LABOUR>();
    protected BindingSource bs = new BindingSource();
    private void PopulateGrid()
    {
        labourCollection = Query.GetLabours();
        bs.DataSource = labourCollection;
        this.dataGridViewX1.DataSource = bs;
    }
    // This method doesn't actually delete Labour from table just mark the column with the present day date. So that it could not be shown in Grid View
    public void btnDel_Click(object sender, EventArgs e)
    {
        if(dataGridViewX1.SelectedRows.Count == 1)
        {
            dataGridViewX1.SelectedRows[0].Cells["WhenDeleted"].Value = DateTime.Now;
        }
        MainForm.GlobalCache.SaveChanges();
        labourCollection = Query.GetLabours();
        //bs.DataSource = labourCollection;  // works when I un comment this line
        bs.ResetBindings(false);  // doesnt work
        }
    }
}

In above, why do I have to write:

//bs.DataSource = labourCollection;  // works when I un comment this line. Why?

Since binding source is already bound to labourCollection in PopulateGrid() method. ResetBinding() should not show record marked for deletion(WhenDeleted not null).

public class Query
{
    internal static List<LABOUR> GetLabours()
    {
   // Getting only those records which are not marked for deletion
      return MainForm.GlobalCache.LABOURs.Local.Where(lab => lab.WhenDeleted == null).ToList();
    }
}

In above GlobalCache is DbContext. Help is appreciated.


Solution

  • Why this code doesn't work?

    labourCollection = Query.GetLabours();
    bs.ResetBindings(false);  
    

    Let's see the reason. There are 2 problem in above code:

    1. labourCollection = Query.GetLabours(); doesn't have any impact on DataSource of bs. It just assigns a new list to labourCollection variable. But previous list is still in memory. labourCollection just points to the new list, but bs uses the list which you assigned to its DataSource property. So the changed item is still there in the list which you used as DataSource of bs.
      Remember reference type concepts. If you assign a new object to a variable, the previous object is untouched. You just missed the pointer to that object and the variable points to the new object.

    2. ResetBindings method just causes a control bound to the BindingSource to reread all the items in the list and refresh their displayed values. It doesn't reload data from database or somewhere else. It just look into DataSource and shows data in the bound control again. So the the value which you changed will be there in list and you can not expect the ResetBindings perform anything special for you.

    So why the this code works?

    labourCollection = Query.GetLabours();
    bs.DataSource = labourCollection;
    bs.ResetBindings(false); 
    

    It works because of bs.DataSource = labourCollection;. The last line of code is useless. When you assign a new list to DataSource of BindingSource it cause refreshing bound controls and you don't need to call ResetBindings.

    What's the usage of ResetBindings?

    It's useful to refresh grid to show values from data source, when the data source doesn't support 2-way data-binding.

    If you change a property of LABOUR in the list using labourCollection[0].Property = "Value"; or even if you remove an item from the list using labourCollection.RemoveAt(0); the DataGridView will not show new value of the Property or even it's not aware of removed item.

    If you call bs.ResetBindings(false) the DataGridView shows new value of property. Also doesn't show the removed item.

    labourCollection[0].SomeProperty = "Some Value";
    bs.ResetBindings(false);