7

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;
    }

}

user1097482
  • 73
  • 1
  • 7

4 Answers4

3

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.

Zohar Peled
  • 79,642
  • 10
  • 69
  • 121
3

it can be easily done by this class:

public class LimitedSizeObservableCollection<T> : ObservableCollection<T>
{
    public int Capacity { get; }

    public LimitedSizeObservableCollection(int capacity)
    {
        Capacity = capacity;
    }

    public new void Add(T item)
    {
        if (Count >= Capacity)
        {
            this.RemoveAt(0);
        }
        base.Add(item);
    }
}
Cinorid
  • 57
  • 5
  • This is not fit for purpose - try using the `Insert` method on a collection of this type that's at capacity and you'll see why. Realistically, this should be an override of the `InsertItem` method (which is what `Add` calls internally anyway). Tried to put this in an edit, but apparently having classes that actually fulfil their intended function is not the original intent of your post? – IAmJersh Sep 27 '22 at 13:20
1

I found another way to limit the number of elements in the collection, without adding a "new" method that breaks compatibility with parent classes:

public class LimitedSizeObservableCollection<T> : ObservableCollection<T>
{
    public int Capacity { get; set; } = 0;

    protected override void InsertItem(int index, T item)
    {
        if (this.Capacity > 0 && this.Count >= this.Capacity)
        {
            throw new Exception(string.Format("The maximum number of items in the list  ({0}) has been reached, unable to add further items", this.Capacity));
        }
        else
        {
            base.InsertItem(index, item);
        }
    }
}
Formentz
  • 1,083
  • 1
  • 14
  • 20
0

If you want it should not add to the collection more than 1000 you can do this.

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

or you can remove the old entries when adding new more than 1000

public ObservableCollection<LogData> LogList
{
    get
    {
        if (logList == null)
        {
            logList = new ObservableCollection<LogData>();
        }
        return logList;
    }
    set
    {
        if(LogList.Count < 1001)
        {
          logList = value;
          OnPropertyChanged("LogList");
        }
        else 
        {
           LogList.RemoveAt(0);
           logList = value;
           OnPropertyChanged("LogList");
        }
    }
}
Shloime Rosenblum
  • 927
  • 11
  • 26