EndlessSpace
EndlessSpace

Reputation: 1380

BeginInvoke not passing data but using Invoke causes exception

I have a windows forms application that shows data in a grid view. The data is being automatically refreshed (fetched from a DB) from a background worker thread. So to avoid any cross thread references, in the DoWork method of the background thread, I call GridView.BeginInvoke() and pass the list of messages. But in the delegate methods, the message list is empty.

If I use GridView.invoke(), the the messageList does contain the values, but sometimes there is an exception which says "object is currently in use elsewhere" which I believe is caused due to referencing UI control on a non-UI thread.

How can I solve this problem?

    public delegate void AddMessagesDelegate(List<ClientMessage> tempMessageList);

    private void SearchWorkerDoWork(object sender, DoWorkEventArgs e)
    {
        List<ClientMessage> partList = new List<ClientMessage>();

        View.GridViewtMain.Invoke(new InvokeDelegate(ClearMessagesFromGrid));
        //View.GridViewtMain.BeginInvoke(new InvokeDelegate(ClearMessagesFromGrid));
        partList.AddRange(Model.LoadSearchResult());
        View.GridViewtMain.Invoke(new AddMessagesDelegate(AddMessagesToGrid), new object[] {partList});
        //View.GridViewtMain.BeginInvoke(new AddMessagesDelegate(AddMessagesToGrid), new object[] {partList});
        while (!isCancelled && (partList.Count > 0))
        {
            partList.Clear();
            partList.AddRange(Model.LoadSearchResult());
            View.GridViewtMain.Invoke(new AddMessagesDelegate(AddMessagesToGrid), new object[] {partList});
            //View.GridViewtMain.BeginInvoke(new AddMessagesDelegate(AddMessagesToGrid), new object[] {partList});
        }
    }

    private void ClearMessagesFromGrid()
    {
        messageDataSource.Clear();
    }

    private void AddMessagesToGrid(List<ClientMessage> tempMessageList)
    {
        View.GridViewMain.BeginDataUpdate();

        foreach (ClientMessage message in tempMessageList)
        {
            messageDataSource.Add(message);
        }
        View.GridViewMain.GridControl.DataSource = messageDataSource;           
        View.GridViewMain.EndDataUpdate();
    }

Upvotes: 0

Views: 696

Answers (1)

Hans Passant
Hans Passant

Reputation: 942368

  partList.Clear();

You posted the code that works instead of the code you have a problem with. I'll assume BeginInvoke instead of Invoke. The partList.Clear() method is going to empty the list, before the delegate target can use the list. You should create a new instance of the list after the BeginInvoke call. The UI thread can now work with the old list without trouble. Roughly

    while (!isCancelled)
    {
        partList = new List<ClientMessage>();
        partList.AddRange(Model.LoadSearchResult());
        if (partList.Count == 0) break;
        View.GridViewtMain.BeginInvoke(new AddMessagesDelegate(AddMessagesToGrid), new object[] {partList});
    }

Upvotes: 2

Related Questions