Reputation: 147
I have this code below which perform async update of an ObservableCollection
of Messages which are collected over an Ethernet Connection
ObservableCollection
private readonly ObservableCollection<MsgDisplayViewModel> _rxGridMessages;
public ObservableCollection<MsgDisplayViewModel> RxGridMessages
{
get { return _rxGridMessages; }
}
Action
_rxMsgUpdater = new Action<RxMessage>((RxMessage msg) =>
{
if (_rxGridMessages.Count < 2000)
{
_rxGridMessages.Add(new MsgDisplayViewModel(msg, DataCollection.DataBase));
}
else
{
var dispmsg = new MsgDisplayViewModel(msg, DataCollection.DataBase);
_rxGridMessages[index++ % _rxGridMessages.Count] = dispmsg;
}
}
);
BeginInvoke
called by Background thread from RxEventHandler
private void RxEventHandler(RxMessage msg)
{
UiDispatcher.BeginInvoke(_rxMsgUpdater, DispatcherPriority.Normal, msg);
}
XAML
<DataGrid Name="TraceGrid"
ItemsSource="{Binding MyVm.RxGridMessages, Mode=OneWay, IsAsync=True}"
SelectionMode="Single" AutoGenerateColumns="False" VirtualizingPanel.IsVirtualizing="True" FontSize="10"
HorizontalAlignment="Stretch" IsReadOnly="True" RowDetailsVisibilityMode="Visible" BorderBrush="{DynamicResource AccentColorBrush}" BorderThickness="1" EnableColumnVirtualization="True"
EnableRowVirtualization="True" ScrollViewer.VerticalScrollBarVisibility="Auto" ScrollViewer.IsDeferredScrollingEnabled="True"
>
<DataGrid.Columns>
...
The UI is fine and good as long as the background thread is calling the RxEventHandler
something like 20 times per second.
Once I put the real traffic in, the RxEventHandler
is called something like 1000 times per second.
So I tried something by extending the ObservableCollection
, I started collecting the changed items on the base OnCollectionChanged
of ObservableCollection
and trigger every 500 ms a CollectionChanged
event.
It obviously threw RangeNotSupportedException
and I had to use the following instead,
try
{
base.OnCollectionChanged(new System.Collections.Specialized.NotifyCollectionChangedEventArgs(System.Collections.Specialized.NotifyCollectionChangedAction.Add, addedItems, itemaddedindex));
}
catch (System.NotSupportedException)
{
base.OnCollectionChanged(new System.Collections.Specialized.NotifyCollectionChangedEventArgs(System.Collections.Specialized.NotifyCollectionChangedAction.Reset));
}
The problem is that the collection is rebuild and there is some delay before it gets displayed. If Collection item count is low it is pretty quick. But when it is 1000 or so then it takes some seconds.
I am feeding this to the datagrid as shown above and I have enabled Virtualization
as well. Now I have done a lot of googling and I have not found someone with a work around for this problem.
Can anybody advice me on this?
I have done some profiling and the CPU hog is PresentationFramework.ni.dll
and it seems related to the numerous CollectionChanged
events.
Right now I have something responsive but at the cost of limiting the Collection count. This is not what I wanted to do.
Upvotes: 0
Views: 789
Reputation: 147
new in Visual Studio 2015
BulkObservableCollection
https://msdn.microsoft.com/en-us/library/dd867973.aspx
Upvotes: 1
Reputation:
Due to the nature of this problem, you should use some type of processing queue and then create a handler that handles the processing sepeerately. Furthermore because of the sheer amount of data you are working with, you should either use a timer to query for new updates every x seconds/minutes and refresh datagrid that way , or you should use some type of virtualizing panel that can handle the sheer amount of data being passed into it(ListView/GridView)
Upvotes: 3