如何在WPF中不挂应用程序的情况下绘制1216个画布元素 [英] How to draw 1216 canvas elements without hanging application in WPF

查看:21
本文介绍了如何在WPF中不挂应用程序的情况下绘制1216个画布元素的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个应用程序,我想添加一些很酷的图标.因为我使用的是漂亮的 MahApps 库,所以我想在 MahApps.Metro/MahApps.Metro.Resources/Icons.xaml 中的图标上有一个视觉效果,所以我做了一些字符串操作来获取 x:Key 每个的一部分; 行.简而言之,我所做的所有字符串操作都得到了以下内容的 1216 个副本:

I am developing an app I want to add some cool icons. Because I am using the beautiful MahApps library, I want to have a visual on the icons in MahApps.Metro/MahApps.Metro.Resources/Icons.xaml, so I did some string manipulations to grab the x:Key part of each <Canvas x:Key="appbar_3d_3ds" Width="76" Height="76" Clip="F1 M 0,0L 76,0L 76,76L 0,76L 0,0"> line. In short, all the string manipulations I did ended up with 1216 copies of the following:

<controls:Tile
Title="appbar_zune" Count="1215" Grid.Row="121" Grid.Column="15" TiltFactor="2" Width="1*" Height="1*"  VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<Rectangle Margin="0" Fill="{Binding RelativeSource={RelativeSource AncestorType=Button}, Path=Foreground}">
<Rectangle.OpacityMask>
<VisualBrush Stretch="Fill"
Visual="{StaticResource appbar_zune}" />
</Rectangle.OpacityMask>
</Rectangle>
</controls:Tile>

请注意, 的每个副本都具有适当的属性 CountGrid.RowGrid.列正确设置.

Note that each copy of the <control:Tile has the appropriate properties Count, Grid.Row and Grid.Column correctly set.

但是,我总是以应用程序无响应窗口消息结束.现在正如我所说的,我的动机只是为了获得漂亮图标集合的视觉效果,而不是导致应用程序崩溃.我只是想知道是否有一种方法可以在不使任何人的计算机崩溃的情况下显示如此庞大的集合(注意:系统内存非常低:我的一台测试机器在 virtualbox 中运行).

However, I always end up with the Application not responding window message. Now as I said, my motive is just to get a visual on that collection of pretty icons and instead I get a fat application crash. I just want to know if there is a way to display such a huge collection without crashing anybody's computer (Note: the system is really low on RAM: one of my test machines that run inside virtualbox).

推荐答案

首先,让您的 Fill 绑定具有 Mode=OneWay.我敢打赌你不需要它是 TwoWay,它可能是你设置中的默认值.TwoWay 绑定的成本要高得多.

First, make your Fill binding have Mode=OneWay. I bet you don't need it to be TwoWay and it may be the defalt in your setup. TwoWay bindings cost much more.

其次,考虑使用更苛刻的版本:Mode=OneTime.由于图标不太可能更改,因此您根本不需要任何更改跟踪.这将为您节省更多资源.

Second, consider using ever harsher version: Mode=OneTime. Since the icons are unlikely to change, you don't need any change tracking at all. This will save you even more resources.

就您而言,First+Second 可能不会给您带来巨大的提升,但值得一试并记住.

In your case, First+Second will probably not give you a huge boost, but it's worth trying and remembering.

第三,你的 VisualBrush 怎么样?它们是否都使用相同的 Visual="{StaticResource appbar_zune}"?那你为什么要创建数千个实例?不要复制粘贴,只需创建一个实例并使所有项目都使用该实例.您可以节省大量时间和内存.

Third, how about your VisualBrushes? Do all of them use the same Visual="{StaticResource appbar_zune}"? Then why do you create thousands of instances? Instead of copy-pasting, create just one instance and make all items use that one instance. You may save much time and memory.

第四,也是最重要的,通常也是最大的加速,是 - 你有的项目.我敢打赌你有一些滚动,水平或垂直.但是您如何生成和显示这些项目呢?一次创建它们是 .. 浪费.它们不适合所有屏幕,对吗?

Fourth, and most important and usually giving the greatest speedup, is - you have tons of items. I bet you have some scrolling, horizontal or vertical. But how do you generate and display those pile of items? Creating them ALL at once is .. wasteful. They don't fit all on screen, right?

您是否有一些 ItemsControl 可以生成那一千个项目?调查该 ItemsControl 的 ItemsPanel 属性并打开该面板上的 virtualizing 选项.这将导致它链接到滚动条,并且它将开始仅动态创建屏幕上的项目并销毁移出屏幕的项目.好吧,我把它简化了,但可以说它是这样工作的.请注意,像 ListBox(以及许多其他容器)这样的容器也是 ItemsControl,因此它也适用于此处.

Do you have some ItemsControl that generate that thousand items? Investigate the ItemsPanel property of that ItemsControl and turn on virtualizing option on that panel. This will cause it to link to the scrollbar and it will start dynamically creating only those items that are on-screen and destroying items that moved off-screen. Well, I oversimplified it, but letssay it works like that. Note that containers like ListBox (and many others) is an ItemsControl too, so it also applies here.

或者,也许您在某些 StackPanel 中没有 ItemsControl 的情况下有包含一千个控件的巨大显式 XAML 文件?这不是很明智.但是哦,好吧.. 你仍然可以在那个 StackPanel 上打开 virtualization.

Or maybe you have huge explicit XAML file with that thousand controls inside some StackPanel with no ItemsControl? That's not really wise. But oh well.. you can still turn on virtualization on that StackPanel.

如果您有几十个以上的项目,打开虚拟化通常是一个好主意.通常,您必须拥有一百个,如果您达到数千个甚至更多,则必须这样做.然而,虚拟化成本:它经常重置/重新初始化项目.如果您的 ItemTemplate 真的很复杂,虚拟化可能会导致滚动变得锯齿/滞后",我不知道如何用英语表达,抱歉.合成线程可能根本没有足够的时间来重新计算和重新布局所有快速移动的项目.如果遇到这个问题,请尝试将项目的 Height 设置为一个不变的真正固定的常量值.它对加快布局有很大帮助.但如果您的 ItemTemplate 真的非常复杂,它也可能无济于事.在这种死胡同的情况下,您唯一的选择是...重新设计并简化项目模板.

Turning on virtualization usually is a good idea if you have more than few tens of items. It's often a must of you have a hundred, and it is a must if you reach thousands and more. However, virtualization costs: it very often resets/reinitializes items. If your ItemTemplate is really complex, virtualization may cause the scrolling to became "jaggy/laggy", I don't know how to express that in english, sorry. The compositor thread may simply not have enough time to recalculate and relayout all the fast moving items. If you hit that problem, try setting the Height of the Items to a unchanging truly fixed constant value. It helps greatly in speeding up the layout. but if your ItemTemplate is really wickedly complex, it may not help either. In such dead-end case your only option is ... redesign and to simplify the item template.

当然,如果您没有滚动条并且试图一次显示大量项目,那么所有这些都不会为您带来任何好处.在这种情况下,努力简化或删除绑定、模板、组件嵌套(有时手动计算位置比使用三个嵌入式网格更好),使用渲染缓存 或 (.....对不起,我开始猜测太多,选择太多..

Of course all of that won't gain you anything if you don't have scrollbar and if you are trying to display a ton of items at once. In this case, strive to simplify or remove Bindings, Templates, component nesting (sometimes it's better to calculate positions manually than using three embeded Grids), use rendering cache or (...).. Sorry, I start making too many guesses, too many options..

我刚刚注意到 Width="1*"Stretch,所以您可能在顶部有一个 Grid,而不是 StackPanel.由于您希望它们的大小相同,UniformGrid 可能具有更好的性能.此外,通过一些工作,您也可以将虚拟化添加到网格中:

I just noticed Width="1*" and Stretch, so you probably have a Grid at the top, not StackPanel. Since you want them equally-sized, the UniformGrid may have better performance. Also, with some work you can add virtualizing to the Grids, too:

  • 从 4.5 开始,它更容易 - 文章:WPF 4.5 新的虚拟化功能
  • 下面,它需要更多的工作,请参阅 Dan Crevier 的 4 部分系列博客:
    • from 4.5 and up, it's much easier - article: WPF 4.5 new virtualizing features
    • below, it requires more work, see Dan Crevier's 4-part series blog:
      • One: http://blogs.msdn.com/dancre/archive/2006/02/06/implementing-a-virtualized-panel-in-wpf-avalon.aspx
      • Two: http://blogs.msdn.com/dancre/archive/2006/02/13/531550.aspx
      • Three: http://blogs.msdn.com/dancre/archive/2006/02/14/532333.aspx
      • Four: http://blogs.msdn.com/dancre/archive/2006/02/16/implementing-a-virtualizingpanel-part-4-the-goods.aspx If virtualizing the Grid is not enough, try moving to Canvas instead and force some width/height/positions manually. Removing automatic layouting sometimes saves a lot. Then, you can use VirtualizedCanvas and if you really put there constant-sized items, you'll probably get it as fast as possible. But that's a last-resort option. Things mentioned earlier should work well.

      哦,还有关于虚拟化的最后一句话:请记住,当 ScrollView 在虚拟化模式下工作时,Position 不再以像素/点计算.v-mode下,滚动条的Position计入items,即position=2.5表示滚动条在第三个item的中途(2个item多半),不是在 pos=2.5像素"处.

      Oh, and one last word about virtualizing: remember that when ScrollView is working in virtualizing mode, then the Position is not counted in pixels/points anymore. In v-mode, the Position of the scrollbar is counted in items, that is, position=2.5 means that the scroller is at halfway through the third item (2 items passed and a half more), not at pos=2.5 "pixels".

      旁注:百万点画布":https://blogs.msdn.microsoft.com/kaelr/2010/08/11/zoomableapplication2-a-million-items/

      这篇关于如何在WPF中不挂应用程序的情况下绘制1216个画布元素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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