为什么WPF的DrawingContext.DrawText这么贵? [英] Why is Wpf's DrawingContext.DrawText so expensive?

查看:885
本文介绍了为什么WPF的DrawingContext.DrawText这么贵?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在WPF(4.0)我的列表框(使用VirtualizingStackPanel)包含500个项目。每个项目都是一个自定义类型



 类页:FrameworkElement的
...
保护覆盖无效的OnRender (的DrawingContext直流)
{
//绘制1000单字符的不同位置
//(formattedText是一个静态构件其仅实例化一次并包含字符串A或b的...)
的for(int i = 0; I< 1000;我++)
dc.DrawText(formattedText,新点(....))


//绘制椭圆1000:非常快,低内存占用
的for(int i = 0; I< 1000;我++)
dc.DrawEllipse(Brushes.Black,空,新的点( ....),10,10)


}

移动列表框的滚动条现在,当来回,使每一个项目的视觉是创造至少一次的RAM使用一段时间,然后后上升到500 MB - 过了一会儿 - 返回到约250 MB,但岿然不动这个水平。内存泄漏 ?我想到了一个VirtualizingStackPanel的优点是,不需要视觉/可视得到处置......



总之,这种极端的RAM的使用只能用的DrawText绘制文本时,会出现。借鉴其他对象,如DrawEllipse不会消耗那么多的内存。



有没有吸引很多文字项比使用Drawing.Context的DrawText的一个更有效的方法是什么?



下面是完整的示例(只需要创建一个新的WPF应用程序项目,并更换窗口1码):(我知道有FlowDocument的和固定文档,但他们别无选择)
的XAML:

 <窗口x:类=WpfApplication1.Window1
的xmlns =http://schemas.microsoft.com/ WinFX的/ 2006 / XAML /演示
的xmlns:X =http://schemas.microsoft.com/winfx/2006/xaml
标题=窗口1HEIGHT =900WIDTH = 800>
<网格背景=黑>
<列表框名称=磅ScrollViewer.CanContentScroll =真的背景=黑>
< ListBox.ItemsPanel>
< ItemsPanelTemplate>
< VirtualizingStackPanel方向=横向/>
< / ItemsPanelTemplate>
< /ListBox.ItemsPanel>
< /列表框>
< /网格和GT;
< /窗GT;



而Window1.xaml.cs:

 公共部分类窗口1:窗口
{
只读的ObservableCollection<&FrameworkElement的GT;收集=新的ObservableCollection<&FrameworkElement的GT;();

公共窗口1()
{
的InitializeComponent();

的for(int i = 0; I< 500;我++)
{
collection.Add(新页(){宽度= 500,高度= 800});
}

lb.ItemsSource =收集;
}
}

公共类页:FrameworkElement的
{
静态FormattedText formattedText =新FormattedText(A,CultureInfo.GetCultureInfo(恩我们),
FlowDirection.LeftToRight,
新字体或符号(新的FontFamily(Arial字体)的ToString()),
12分配,Brushes.Black)。
保护覆盖无效的OnRender(DC的DrawingContext)
{
dc.DrawRectangle(Brushes.White,空,新的矩形(0,0,宽度,高度));
双YOFF = 0;
的for(int i = 0; I< 1000;我++)//画1000AS
{
dc.DrawText(formattedText,新的点((我80%)* 5,YOFF));
如果(I%80 == 0)YOFF + = 10;

}

}

}


< DIV CLASS =h2_lin>解决方案

虽然这不是对你有用的全部,我的经验VirtualizingStackPanel是不是其配置不在视图中的对象,但它允许对象不是视图将予出售,当应用程序需要更多的内存,这将导致您的内存使用气球当有可用内存以恢复内存。



难道dc.DrawText是射击BuildGeometry()每个formattedText对象,你可以把那个外循环?我不知道BuildGeometry多少工作,但它有可能是的DrawingContext只能够接受的几何形状,以及样品在BuildGeometry呼叫无需调用的999倍。看看:



http://msdn.microsoft.com/en-us/library/system.windows.media.formattedtext.aspx



看看是否有任何其他的优化,你可以做到的。



你能输出一些内存配置文件数据和环路内的一些时序数据给出的感觉无论是放缓下来,或存储器中的非线性方式循环期间增加


In Wpf (4.0) my listbox (using a VirtualizingStackPanel) contains 500 items. Each item is of a custom Type

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)


}

Now when moving the scrollbar of the listbox back and forth so that every item's visual is created at least once the ram usage goes up to 500 Mb after a while and then - after a while - goes back to ca 250 Mb but stays on this level. Memory leak ? I thought the advantage of a VirtualizingStackPanel is that visuals which are not needed/visible get disposed...

Anyway, this extreme ram usage only appears when drawing text using "DrawText". Drawing other objects like "DrawEllipse" does not consume so much memory.

Is there a more efficient way to draw many text items than using Drawing.Context's "DrawText" ?

Here is the complete sample (just create a new Wpf Application project and replace the window1 code): (I know there are FlowDocument and FixedDocument but they are no 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>

And the 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;

        }

    }

}

解决方案

While this isn't entirely useful to you, my experience with VirtualizingStackPanel isn't that it disposes of objects not in view, but that it allows objects not in view to be disposed to recover memory when the application needs more memory, which should result in your memory usage ballooning when there is memory available.

Is it possible that dc.DrawText is firing BuildGeometry() for each formattedText object, and that you can bring that outside the loop? I don't know how much work BuildGeometry is, but it's possible that the DrawingContext is only capable of accepting geometry, and the BuildGeometry call is being called unnecessarily 999 times in your sample. Have a look at:

http://msdn.microsoft.com/en-us/library/system.windows.media.formattedtext.aspx

to see whether there are any other optimizations you can make.

Can you output some memory profile data and some timing data within your loops to give a sense of whether it's slowing down, or the memory is increasing in a non-linear fashion during the loop?

这篇关于为什么WPF的DrawingContext.DrawText这么贵?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆