In Wpf (4.0) la mia listbox (che utilizza un VirtualizingStackPanel) contiene 500 articoli. Ogni elemento è di tipo personalizzatoPerché il DrawingContext.DrawText di Wpf è così costoso?
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)
}
Ora, quando si sposta la barra di scorrimento della casella di riepilogo avanti e indietro in modo che di visual ogni elemento viene creato almeno una volta l'utilizzo della RAM va fino a 500 Mb, dopo un po 'e poi - dopo un po '- torna a circa 250 Mb ma rimane su questo livello. Perdita di memoria ? Ho pensato che il vantaggio di un VirtualizingStackPanel è che le immagini che non sono necessarie/visibili vengono smaltite ...
In ogni caso, questo uso estremo della ram viene visualizzato solo quando si disegna il testo usando "DrawText". Disegnare altri oggetti come "DrawEllipse" non consuma così tanta memoria.
Esiste un modo più efficiente di disegnare più elementi di testo rispetto all'utilizzo di "DrawText" di Drawing.Context?
Ecco l'esempio completo (basta creare un nuovo progetto WPF Applicazione e sostituire il codice Window1): (so che ci sono FlowDocument e FixedDocument ma sono alternative) 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>
E il 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;
}
}
}
Si potrebbe provare StreamGeometry. Quale è relativamente leggero. http://msdn.microsoft.com/en-us/library/ms742199.aspx D'altra parte. Devo dire. DrawText è una cosa relativamente meno pesata. Non so perché sta prendendo molte risorse. Avete qualche campione per lo scenario sopra? –
DrawingContext.DrawGlyph sembra essere molto più veloce di DrawText. – fritz