这个问题与我最近发布的一个问题直接相关,但我觉得方向已经发生了足够的变化,需要一个新的问题。我试图找出在画布上实时移动大量图像的最佳方法。我的 XAML 目前看起来像这样:
<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; }
}
要移动对象:
private Action<Entity> action = (Entity entity) =>
{
entity.Location = new Vector(entity.Location.X + 1, entity.Location.Y);
};
void Timer_Tick(object sender, EventArgs e)
{
Task.Factory.StartNew(() =>
{
foreach (var entity in Locator.Container.Entities)
{
action(entity);
}
});
}
如果集合中的条目少于大约 400 个,则Entities
移动很顺畅,但我希望能够将这个数字增加很多。如果我超过 400,运动会变得越来越不稳定。起初我认为这是运动逻辑的问题(在这一点上这并不是什么大问题),但我发现这不是问题。我添加了另一个包含 10,000 个条目的集合,并将该集合添加到与第一个集合相同的计时器循环中,但未将其包含在 XAML 中,并且 UI 的反应没有任何不同。然而,我觉得奇怪的是,如果我将 400 个条目添加到集合中,然后在 Image 设置为 400 的情况下再添加 400 个条目,null
即使有一半的项目没有被绘制,移动也会变得不稳定。
那么,我该怎么做才能在画布上绘制和平滑移动更多图像呢?这是我可能想回避 WPF 和 XAML 的情况吗?如果您需要更多代码,我很乐意发布。
更新:根据 Clemens 的建议,我的Entity
DataTemplate 现在看起来像这样:
<DataTemplate DataType="{x:Type local:Entity}">
<Image Width="{Binding Width}"
Height="{Binding Height}"
Source="{Binding Image}">
<Image.RenderTransform>
<TranslateTransform X="{Binding Location.X}" Y="{Binding Location.Y}" />
</Image.RenderTransform>
</Image>
</DataTemplate>
使用它可能会提高性能,但如果有的话,它是非常微妙的。另外,我注意到如果我使用DispatcherTimer
for 循环并将其设置为:
private DispatcherTimer dTimer = new DispatcherTimer();
public Loop()
{
dTimer.Interval = TimeSpan.FromMilliseconds(30);
dTimer.Tick += Timer_Tick;
dTimer.Start();
}
void Timer_Tick(object sender, EventArgs e)
{
foreach (var entity in Locator.Container.Entities)
{
action(entity);
}
}
...即使有几千个项目,运动也很流畅,但无论间隔如何,都非常缓慢。如果DispatcherTimer
使用 a 并且Timer_Tick
看起来像这样:
void Timer_Tick(object sender, EventArgs e)
{
Task.Factory.StartNew(() =>
{
foreach (var entity in Locator.Container.Entities)
{
action(entity);
}
});
}
...运动非常不稳定。我觉得奇怪的是,如果有 5,000 个条目,则 aStopwatch
表明Task.Factory
需要 1000 到 1400 个滴答来迭代集合。标准foreach
循环需要超过 3,000 个滴答声。Task.Factory
当它的速度是原来的两倍时,为什么会表现得如此糟糕?是否有不同的方法来遍历集合和/或不同的计时方法,可以允许平滑移动而不会出现任何重大减速?
更新:如果有人可以帮助我提高画布上对象实时移动的性能,或者可以在 WPF 中提出另一种实现类似结果的方法,100 赏金等待。