Search code examples
c#data-bindingobservablecollection

.net c# Limit number of entries in observablecollection


I having a WPF application in which the UI has a list box. The list box has binding of ObservableCollection. Log class implements INotifyPropertyChanged.

The list will show the continuous logging of the application. As long as the application is running. The ObservableCollection size keeps on growing. After some time I get the Out of Memory exception. I want to show the latest 1000 entries in the list control. Any suggestions on this will be of great help!!

XAML:

                    <DataGrid AutoGenerateColumns="False" SelectedValue="{Binding SelectedLog}" SelectionUnit="FullRow" SelectionMode="Single" Name="dataGridLogs" 
                      ItemsSource="{Binding Path=LogList}"  CanUserReorderColumns="True" CanUserResizeRows="True" CanUserDeleteRows="False"  IsReadOnly="True"
                      CanUserAddRows="False" EnableColumnVirtualization="True" EnableRowVirtualization="True" SelectionChanged="grid_SelectionChanged"> 
                <DataGrid.Columns>
                    <DataGridTextColumn Header="Time Stamp" Binding="{Binding StrTimeStamp, Mode=OneWay}" Width="Auto"/>
                    <DataGridTextColumn Header="Action" Binding="{Binding Action, Mode=OneWay}" Width="Auto"/>

            </DataGrid>

ViewModel:

    public ObservableCollection<LogData> LogList
    {
        get
        {
            if (logList == null)
            {
                logList = new ObservableCollection<LogData>();
            }
            return logList;
        }
        set
        {
            logList = value;
            OnPropertyChanged("LogList");
        }
    }

model:

     public class LogData : INotifyPropertyChanged
{
    public LogData()
    {
    }
    private String timestamp = string.Empty;
    public String StrTimestamp
    {
        get
        {
            if (timestamp == null)
                return string.Empty;
            return timestamp ;
        }
        set
        {

            timestamp = value;
        }
    }
    public string Action
    {
       get;set;
    }

}


Solution

  • You could create your own size limited observable collection class. Something like this should get you started:

    public class LimitedSizeObservableCollection<T> : INotifyCollectionChanged
    {        
        private ObservableCollection<T> _collection;
        private bool _ignoreChange;
    
        public LimitedSizeObservableCollection(int capacity)
        {
            Capacity = capacity;
            _ignoreChange = false;
            _collection = new ObservableCollection<T>();
            _collection.CollectionChanged += _collection_CollectionChanged;
        }
    
        public event NotifyCollectionChangedEventHandler CollectionChanged;
    
        public int Capacity {get;}
    
        public void Add(T item)
        {
            if(_collection.Count = Capacity)
            {
                _ignoreChange = true;
                _collection.RemoveAt(0);
                _ignoreChange = false;
            }
            _collection.Add(item);
    
        }
    
        private void _collection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if(!_ignoreChange)
            {
                CollectionChanged?.Invoke(this, e);
            }
        }
    }
    

    Of course, you will probably have to expose some more methods, but I hope that's enough for you to get the idea.