What would be the most efficient way to iterate through a collection with a large number of items (1,000 or more) and update the items' properties in real-time? At the moment, my program draws an image for each object in the collection on a canvas using WriteableBitmap
(though I don't see any difference in performance between that an a simple ellipse) and moves it across the screen. I am trying to keep the logic as simple as possible for the time being.
<UserControl.Resources>
<DataTemplate DataType="{x:Type local:Entity}">
<Canvas>
<Image Canvas.Left="{Binding Location.X}"
Canvas.Top="{Binding Location.Y}"
Width="{Binding Width}"
Height="{Binding Height}"
Source="{Binding Image}" />
</Canvas>
</DataTemplate>
</UserControl.Resources>
<Canvas x:Name="content"
Width="2000"
Height="2000"
Background="LightGreen">
<ItemsControl Canvas.ZIndex="2" ItemsSource="{Binding Entities}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas IsItemsHost="True" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
[Magic]
public class Entity : ObservableObject
{
public Entity()
{
Height = 16;
Width = 16;
Location = new Vector(Global.rand.Next(800), Global.rand.Next(800));
Image = Global.LoadBitmap("Resources/Thing1.png");
}
public int Height { get; set; }
public int Width { get; set; }
public Vector Location { get; set; }
public WriteableBitmap Image { get; set; }
}
(In the Entity class above, the [Magic] attribute implements INPC on all of my properties)
I have tried using System.Timers.Timer
, System.Threading.Timer
, and System.Threading.DispatcherTimer
to create a loop with varying intervals. All behave fairly well until I get to about 800 objects in the collection and then they start to become choppy. I have also tried using a standard foreach
loop and a Parallel.ForEach
loop and haven't really noticed a difference between the two. My loop had more complex logic, but I have made it as simple as possible until I can figure out how to streamline the process:
void Timer_Tick(object sender, EventArgs e)
{
Parallel.ForEach(Entities, entity =>
{
entity.Location = new Vector(entity.Location.X + 1, entity.Location.Y);
});
}
(Also, this isn't an issue with the Canvas; if I draw 10 items and make 1,000 with no image it still gets choppy.)
What can I do to make my program handle large collections in real-time more efficiently? I'm guessing there's a good bit I'm missing as this is the first time I've ever dealt with anything of this nature. Any advice would be greatly appreciated.