1

I have a windows form which has the following code

BindingList<TicketResult> tickResults = new BindingList<TicketResult>();
BindingSource bindingSource1 = new BindingSource();
Action<String> call;

private void method(String x)
{
    if (this.dataGridView1.InvokeRequired)
    {
        lock (this)
        {                    
            dataGridView1.Invoke(
            new MethodInvoker(() =>
            {
                Debug.WriteLine(x);
                tickResults[int.Parse(x)].Row = "first page";
                dataGridView1.Refresh();
            }));
        }
    }
}

public Form1()
{
    call = method;

    ServicePointManager.DefaultConnectionLimit = 48;
    InitializeComponent();

    tickResults.ListChanged += tickResults_ListChanged;

    for (int i = 0; i < 10; i++)
    {
        TicketResult result = new TicketResult();                
        tickResults.Add(result);
    }

    bindingSource1.DataSource = tickResults;

    dataGridView1.DataSource = bindingSource1;


    for (int i = 0; i < 10; i++)
    {
        Search s = new Search();
        int x = i;
        Task.Run(() => s.start(x, this.call));
    }


}

I don't understand why the change in tickResults is not reflected without calling dataGridView1's Refresh() method.

Code for other classes which call the "call" delegate in the form are as follows:

class Search : ISearch
{
    public async Task<bool> start(int i, Action<String> x)
    {
        bool result = false;
        TicketLogic tixLogic = new TicketLogic();

        try
        {
            await Task.Run(() => tixLogic.processFirstPage(i, x))
                .ContinueWith((t) => tixLogic.processSecondPage(i, x))
                .ContinueWith((t) => tixLogic.processThirdPage(i, x));               

            result = true;
        }
        catch (Exception e)
        {
            Debug.WriteLine(e.Message);
            result = false;
        }

        return result;
    }

    public async Task<bool> stop()
    {
        return false;
    }

    public async Task<bool> restart()
    {
        return false;
    }
}

class TicketLogic
{
    public async Task<bool> processFirstPage(int i, Action<String> x)
    {
        bool result = false;            

        try
        {
            HttpWebRequest request = WebRequest.CreateHttp("http://www.google.com");
            WebResponse response = await request.GetResponseAsync();
            StreamReader reader = new StreamReader(response.GetResponseStream());

            String textResponse = await reader.ReadToEndAsync();                

            reader.Close();
            response.Close();              

            result = true;
        }
        catch (Exception e)
        {
            Debug.WriteLine(e.Message);
            result = false;
        }

        return result;
    }

    public async Task<bool> processSecondPage(int i, Action<String> x)
    {
        bool result = false;            

        try
        {
            HttpWebRequest request = WebRequest.CreateHttp("http://www.example.com");
            WebResponse response = await request.GetResponseAsync();
            StreamReader reader = new StreamReader(response.GetResponseStream());

            String textResponse = await reader.ReadToEndAsync();

            //tixResult.Information = "Second Page";

            reader.Close();
            response.Close();

            x(i.ToString());

            result = true;
        }
        catch (Exception e)
        {
            Debug.WriteLine(e.Message);
            result = false;
        }

        return result;
    }

    public async Task<bool> processThirdPage(int i, Action<String> x)
    {
        bool result = false;

        try
        {
            HttpWebRequest request = WebRequest.CreateHttp("http://www.hotmail.com");
            WebResponse response = await request.GetResponseAsync();
            StreamReader reader = new StreamReader(response.GetResponseStream());

            String textResponse = await reader.ReadToEndAsync();

            //tixResult.Information = "Third Page";

            reader.Close();
            response.Close();

            x(i.ToString());

            result = true;
        }
        catch (Exception e)
        {
            Debug.WriteLine(e.Message);
            result = false;
        }
        return result;
    }
}

Before this I tried one more approach, in which I was passing the databound object to a computation Task, where the databound object got manipulated, but even there the result was the same i.e. the changes in the object were not reflected upon the grid until I clicked some Cell in the Grid or minimized/maximized the form.

My question is, why are the changes not being reflected in the Grid without calling datagrid refresh() ??

TaW
  • 53,122
  • 8
  • 69
  • 111
sp3tsnaz
  • 506
  • 7
  • 16
  • possible duplicate of [Best way to refresh DataGridView when you update the base data source](http://stackoverflow.com/questions/253843/best-way-to-refresh-datagridview-when-you-update-the-base-data-source) – Dimitris Batsougiannis Aug 14 '15 at 12:20
  • Maybe the powers that be decided that constant automatic refreshing is not good for e.g. performance or even user experience. So they leave it to you to decide just when all updates are through to to trigger a Refresh.. – TaW Aug 14 '15 at 17:57
  • @TaW: Doesn't make sense. If I add a button to the form which upon clicking adds an object to the data source to which the bindingsource is bound, it displays the change in the grid automatically. Why is refresh not needed there ? – sp3tsnaz Aug 15 '15 at 19:08
  • Well I didn't design it, but your example doesn't contradict my suggestion but supports it. A Click happens on the UI, so the UI should be current. Changes to the datasource from code could happen multiple times in a row and a flickering UI would not be nice.. – TaW Aug 15 '15 at 19:15
  • @TaW: The point is not to contradict, but to understand the reason behind it. – sp3tsnaz Aug 15 '15 at 19:16
  • Have you resolved your problems? – TaW Aug 26 '15 at 10:52

2 Answers2

0

Try using ObservableCollection instead of BindingList The Observable implements the INotifyPropertyChange which notifies the DataGridView when something changes

0

It is often difficult to answer question like this as we don't usually have access to the reasoning of the .NET designers.

So I'll try to make sense of it by guessing; I hope this not just helps you to understand but also to accept and make the best of it..

Maybe the powers that be decided that constant automatic refreshing is not good for e.g. performance or even user experience. So they leave it to you to decide just when all updates are through to to trigger a Refresh..

There is a big difference between a Click and calls from code, let alone from other tasks. A Click happens on the UI, so the UI should be current. Changes to the datasource from code could happen multiple times in a row, at any frequency and a flickering UI would not be nice..

Let's try to change the perspective: Instead of seeing the issue at hand as a tedious extra task one could see it as a chance to control the times when the refresh happens.

Or to change the perspective even further: You can prevent the user from being flooded with updates when he maybe really would prefer a Refresh button and maybe an unobtrusive count of outstanding changes or new records..

TaW
  • 53,122
  • 8
  • 69
  • 111