Andrew Stephens
Andrew Stephens

Reputation: 10193

Am I using the collection view properly?

I have a view/view-model that simply displays a list of "log entries", with the most recent item at the top. The user is also able to toggle a few settings on and off to restrict which types of log entry appear in the list. The problem is that the application starts running slower and slower as the number of log items increases, with the ItemsControl flickering and flashing.

Here is the VM code (irrelevant code removed for brevity):

public class ApplicationLogViewModel
{
    private readonly List<ApplicationLogEntry> _allLogEntries = new List<ApplicationLogEntry>();

    // Bound to an ItemsControl in the view
    public ICollectionView LogEntries { get; private set; }

    // Ctr
    public ApplicationLogModel(IApplicationLogService applicationLogService)
    {
        LogEntries = CollectionViewSource.GetDefaultView(_allLogEntries);

        applicationLogService.MessageLogged += MessageLogged;
    }    

    // Event handler to add new log entries to list
    private void MessageLogged(object sender, ApplicationLogEntry logEntry)
    {
        var count = _allLogEntries.Count;
        if (count >= 100)
        {
            _allLogEntries.RemoveAt(count - 1);
        }

        _allLogEntries.Insert(0, logEntry);

        Dispatcher.CurrentDispatcher.Invoke(() => LogEntries.Refresh());
    }
}

A "IApplicationLogService" raises events as messages are logged, and this event is handled in the MessageLogged() method above, which simply adds the new item to the start of the internal collection (so you get the most recent item at the top of the list), then refreshes the collection view (done via the Dispatcher as the event is not raised on the UI thread). The code also limits the list to 1000 items, but the problem is noticeable long before this - usually once there are approx 100 items.

I've omitted the code that sets the collection view's Filter (based on some bool property states), as the slowdown occurs even with LogEntries.Filter = null.

I understand that the call to Refresh() is resulting in a complete update/redraw of the list, hence the performance problems. So the question is - am I using the collection view correctly, or is there a more efficient way to achieve what I'm trying to do?

Upvotes: 1

Views: 51

Answers (1)

Nitro.de
Nitro.de

Reputation: 851

The easiest way is to change your List<ApplicationLogEntry> _allLogEntries to ObservableCollection<ApplicationLogEntry> _allLogEntries and use Databinding on that. The UI will notice every change in the Collection on it's own and will remove / reload whats needed. If you need a little tutorial on Databinding this one here helped me a lot.

Upvotes: 1

Related Questions