简体   繁体   中英

DataGridView not updating in UI when underlying datasource changes

I am creating a small Windows Form application that will receive messages from a background thread and then add them to a List on the Main form. On the form I have a DataGridView with the DataSource set to the message list ( eg List<Message> )

At the moment, messages are piling up but I can't get the DataGridView to render the messages as they arise. Here is a summary of the approach I have used.

1. Initialize the main form setting the binding and startnig the message routines

internal Main(IMessageDispatcher messageDispatcher, IMessagePublisher messagePublisher)
{
    InitializeComponent();

    _messageEntries = new List<Message>();

    BindToMessageEntriesList();

    _messageDispatcher = messageDispatcher;
    _messageDispatcher.OnMessageReceived += MessageDispatcher_OnMessageReceived;
    _messageDispatcher.Start();
}

private void BindToMessageEntriesList()
{
    MessageEntriesGrid.DataSource = _messageEntries;
}

2. Process received messages and add to the internal list

private void MessageDispatcher_OnMessageReceived(Message message)
{
    lock (_logEntries)
    {
        _messageEntries.Add(message);
    }

    var cb = new RefreshListCallbackDelegate(RefreshView);
    this.Invoke(cb);
}

3. Refresh on the main thread

private void RefreshView()
{
    MessageEntriesGrid.Refresh();
}

Can anyone suggest how I can get the UI to reflect the changes as they occure.

Note: I have also tried using the Invalidate method and the ResetBindings method. I also tried switching the List to an ObservableCollection

DataGridView won't update its display automatically when you bind a List to it and then modify the original List. It will only display the data that existed in the list at the time you bound it.

If you want the DataGridView to dynamically update when the bound collection changes, you need to bind a collection that implements IBindingList (like BindingList http://msdn.microsoft.com/en-us/library/ms132679(v=vs.90).aspx ) or IBindingListView (like BindingSource http://msdn.microsoft.com/en-us/library/system.windows.forms.bindingsource(v=vs.90).aspx ).

You can replace the List<Message>() to a custom class and inherits of BindingList<T> and attach your Message Dispatcher into it. Example

public class MessageList : BindingList<Message>
{
}

in your main form subsribe the ListChanged event and you good to go.

When Ever I do anything with datagridview like this I use the following system :-

I have a DataObject, In your case a List object. I then create a Binding Object and set its datasource as the DataObject. I the set the DatagridView DataSource as the Binding Object.

That way, when your making changes to The Data Object, they filter through to the Datgrid Automatically.

In your case, you should do as Turbot Says, create a class that inherits the BindingList object, and you are good to go.

Try using a BindingList instead of List . It forms a two-way connection. (It's in the ComponentModel namespace)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM