В Wpf (4.0) мой список (с использованием VirtualizingStackPanel) содержит 500 элементов. Каждый элемент имеет пользовательский тип
class Page : FrameworkElement
...
protected override void OnRender(DrawingContext dc)
{
// Drawing 1000 single characters to different positions
//(formattedText is a static member which is only instantiated once and contains the string "A" or "B"...)
for (int i = 0; i < 1000; i++)
dc.DrawText(formattedText, new Point(....))
// Drawing 1000 ellipses: very fast and low ram usage
for (int i = 0; i < 1000; i++)
dc.DrawEllipse(Brushes.Black, null, new Point(....),10,10)
}
Теперь при перемещении полосы прокрутки списка назад и вперед, чтобы визуальный элемент каждого элемента создавался по крайней мере после того, как через некоторое время использование оперативной памяти увеличилось до 500 МБ, а затем - через некоторое время - возвращается примерно к 250 МБ, но остается на этом уровне . Утечка памяти ? Я думал, что преимущество VirtualizingStackPanel заключается в том, что визуальные эффекты, которые не нужны/видимы, удаляются...
В любом случае, это экстремальное использование оперативной памяти проявляется только при рисовании текста с помощью «DrawText». Рисование других объектов, таких как «DrawEllipse», не требует много памяти.
Есть ли более эффективный способ рисования большого количества текстовых элементов, чем использование "DrawText" Drawing.Context?
Вот полный пример (просто создайте новый проект приложения Wpf и замените код window1): (я знаю, что есть FlowDocument и FixedDocument, но они не являются альтернативой) Xaml:
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="900" Width="800">
<Grid Background="Black">
<ListBox Name="lb" ScrollViewer.CanContentScroll="True" Background="Black">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
</Grid>
</Window>
И Window1.xaml.cs:
public partial class Window1 : Window
{
readonly ObservableCollection<FrameworkElement> collection = new ObservableCollection<FrameworkElement>();
public Window1()
{
InitializeComponent();
for (int i = 0; i < 500; i++)
{
collection.Add(new Page(){ Width = 500, Height = 800 });
}
lb.ItemsSource = collection;
}
}
public class Page : FrameworkElement
{
static FormattedText formattedText = new FormattedText("A", CultureInfo.GetCultureInfo("en-us"),
FlowDirection.LeftToRight,
new Typeface(new FontFamily("Arial").ToString()),
12,Brushes.Black);
protected override void OnRender(DrawingContext dc)
{
dc.DrawRectangle(Brushes.White, null, new Rect(0, 0, Width, Height));
double yOff = 0;
for (int i = 0; i < 1000; i++) // draw 1000 "A"s
{
dc.DrawText(formattedText, new Point((i % 80) * 5, yOff ));
if (i % 80 == 0) yOff += 10;
}
}
}