W8.1: Given to Fly
This is a modal window.
The media could not be loaded, either because the server or network failed or because the format is not supported.
Formal Metadata
Title |
| |
Alternative Title |
| |
Title of Series | ||
Number of Parts | 170 | |
Author | ||
License | CC Attribution - NonCommercial - ShareAlike 3.0 Unported: You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal and non-commercial purpose as long as the work is attributed to the author in the manner specified by the author or licensor and the work or content is shared also in adapted form only under the conditions of this | |
Identifiers | 10.5446/50814 (DOI) | |
Publisher | ||
Release Date | ||
Language |
Content Metadata
Subject Area | ||
Genre | ||
Abstract |
|
NDC Oslo 2014100 / 170
2
3
5
6
8
11
12
16
21
22
23
27
31
35
37
42
43
45
47
48
49
50
52
54
56
57
58
61
65
66
67
71
74
77
80
81
83
84
85
87
88
89
90
91
94
95
96
97
98
100
102
107
108
112
114
115
116
118
120
121
122
123
126
127
128
130
133
135
137
138
139
140
141
142
143
144
145
147
148
149
150
153
155
156
157
158
159
160
161
162
163
166
169
170
00:00
IRIS-TWindowEmailData storage deviceClient (computing)Address spaceCASE <Informatik>Mobile appUniform resource locatorComputer architectureApache ForrestReal numberCartesian coordinate systemCross-platformTwitterMobile WebComputer animation
01:19
ArchitectureData dictionaryTemplate (C++)Visualization (computer graphics)VirtualizationThread (computing)Task (computing)MultiplicationSemiconductor memoryMessage passingCodeCellular automatonComputer fileTask (computing)Data dictionaryMoment (mathematics)Proof theoryCalculationCartesian coordinate systemFlow separationVirtualizationWeb pageType theoryDefault (computer science)TouchscreenSynchronizationField (computer science)Software frameworkComputer architectureSlide ruleEvent horizonElement (mathematics)CASE <Informatik>Right angleDependent and independent variablesDressing (medical).NET FrameworkPoint (geometry)Sampling (statistics)Source codeDegree (graph theory)Computer hardwareMereologyNegative numberStrategy gameBuildingDemosceneObject (grammar)Data storage deviceProfil (magazine)KnotTemplate (C++)Self-organizationNumberInsertion lossForm (programming)Position operatorTranslation (relic)Primitive (album)BitWeightPersonal area networkDemo (music)Mobile appMultiplication signWindowComputer animation
07:18
Element (mathematics)Category of beingPixelRectangleBefehlsprozessorThread (computing)First-person shooterBit ratePhysical systemTouchscreenInstance (computer science)Virtual machineSign (mathematics)Semiconductor memorySolid geometryGraph coloringNumberElement (mathematics)RectangleSoftware developerPhysical systemRight angleTask (computing)Water vaporStructural loadAbsolute valueType theoryLevel (video gaming)Category of beingDrop (liquid)Medical imagingPixel10 (number)Set (mathematics)Software frameworkComputer hardwareCASE <Informatik>Row (database)Inheritance (object-oriented programming)2 (number)GradientPoint (geometry)Direction (geometry)ResultantVirtualizationCartesian coordinate systemCodeDisk read-and-write headSound effectCountingBitElectronic mailing listDemo (music)Mobile appBefehlsprozessorExistential quantificationGraphics processing unitFrame problemMetropolitan area networkData dictionaryArmView (database)Thread (computing)CuboidComputer animation
13:17
Demo (music)Software development kitVacuumElectronic mailing listTouchscreenTemplate (C++)Right angleNumberRegular graphView (database)RectangleFrame problemGradientComputer animation
15:11
Demo (music)Visual systemMenu (computing)Duality (mathematics)Convex hullInvariant (mathematics)Template (C++)Element (mathematics)Computer hardwareSound effectPixelSoftware testingFluid staticsResultantComputer animationPanel painting
16:13
Demo (music)GeometryComputer iconUniversal product codeNormed vector spaceVacuumCountingStructural loadSoftware developerSampling (statistics)Virtual machineDifferent (Kate Ryan album)Multiplication signElement (mathematics)CodeThread (computing)ArmTablet computerComputer animationPanel painting
17:09
GUI widgetDefault (computer science)Data dictionaryLatent heatWeb pageCache (computing)VirtualizationElectronic mailing listRead-only memoryControl flowView (database)Stack (abstract data type)Sampling (statistics)Game controllerData structureDefault (computer science)Web pageElectronic mailing listThread (computing)Data dictionaryView (database)WindowTemplate (C++)Instance (computer science)State of matterVisualization (computer graphics)Semiconductor memoryElement (mathematics)VirtualizationMobile appGroup actionCuboidData storage deviceCodeDifferent (Kate Ryan album)TouchscreenType theoryBoolean algebraMultiplication signKeyboard shortcutGoodness of fitMedical imagingSocial classCASE <Informatik>Object (grammar)ParsingBasis <Mathematik>Rule of inferenceLevel (video gaming)Latent heatCategory of beingData managementDemo (music)Cartesian coordinate systemMoment (mathematics)Strategy gamePresentation of a groupCovering spacePoint (geometry)Ultraviolet photoelectron spectroscopyPressureWorkstation <Musikinstrument>WebsiteVariable (mathematics)Right angleMessage passingBit rateTunisActuaryVideo gameMechatronicsOverlay-NetzMilitary baseNetwork topologyComputer animationMeeting/Interview
26:41
Duality (mathematics)Menu (computing)Semiconductor memoryRight angleProfil (magazine)View (database)VirtualizationResultantDifferent (Kate Ryan album)Fitness functionGroup actionWebsiteCASE <Informatik>Computer animation
28:28
Demo (music)Medical imagingBitTouchscreenExistential quantificationSpeciesObservational studyComputer animationPanel painting
29:15
Term (mathematics)Maxima and minimaLemma (mathematics)MathematicsGamma functionOvalExecution unitDampingDemo (music)Type theoryView (database)Instance (computer science)VirtualizationData storage deviceSemiconductor memoryWindowSource codeBitData dictionaryCASE <Informatik>Default (computer science)Presentation of a groupReflection (mathematics)Intelligent NetworkOrder (biology)Term (mathematics)Goodness of fitMobile appPoint (geometry)GradientBit rateComputer animation
32:15
Demo (music)Dynamic random-access memoryEmulationMaxima and minimaTelephone number mappingInferenceLemma (mathematics)BitInstance (computer science)Core dumpGroup actionInheritance (object-oriented programming)Semiconductor memoryTouchscreenMultiplication signNetwork topologyDifferent (Kate Ryan album)VirtualizationPairwise comparisonComputer animationPanel painting
33:47
Control flowAreaVirtualizationContent (media)Inheritance (object-oriented programming)Visualization (computer graphics)Inheritance (object-oriented programming)Content (media)Game controller40 (number)AreaView (database)TouchscreenWhiteboardCASE <Informatik>Clique-widthVirtualizationElectronic mailing listSound effectElectronic visual displayVisualization (computer graphics)Group actionWeightCartesian coordinate systemComputer animation
35:38
Duality (mathematics)View (database)Axiom of choiceSet (mathematics)VirtualizationClique-widthComputer animation
36:33
Demo (music)Visual systemCore dumpGoodness of fitRight angleFile viewerVirtualizationInstance (computer science)Group actionWeb pageGame controllerInheritance (object-oriented programming)View (database)Clique-widthComputer animation
38:18
VirtualizationSubsetImplementationFree variables and bound variablesSynchronizationSubsetVirtualizationElectronic mailing listPosition operatorElement (mathematics)RandomizationRandom accessType theoryCategory of beingData storage deviceCASE <Informatik>Structural loadImplementationMobile appFree variables and bound variablesWindowSystem callLevel (video gaming)Directed graphMathematicsLatent heatComputer animation
40:37
Gamma functionDemo (music)Degree (graph theory)VirtualizationExtension (kinesiology)Noise (electronics)Profil (magazine)CASE <Informatik>Electronic mailing listSemiconductor memoryGoodness of fitVirtualizationBitRandomizationMultiplication signTwitterComputer animation
41:52
Information managementNormed vector spaceExecution unitPrice indexCountingOvalSynchronizationInclusion mapMaxima and minimaRAIDArmCuboidFront and back endsElectronic mailing listMereologyBlogKeyboard shortcutCodeMultiplication signView (database)ImplementationCategory of beingData dictionaryMathematicsBitSubject indexingInterface (computing)Position operatorFree variables and bound variablesDirected graphBlock (periodic table)Group actionStructural loadHoaxNetwork topologyRandomizationCASE <Informatik>Computer animation
45:10
VirtualizationImplementationVirtualizationRandomizationInsertion lossRandom accessInterface (computing)Structural loadComputer animation
45:58
Degree (graph theory)Demo (music)IRIS-TStochastic differential equationGamma functionExecution unitThomas KuhnString (computer science)Annulus (mathematics)Menu (computing)1 (number)Convex hullMultiplicationWeb pageMaß <Mathematik>Structural loadDemo (music)TouchscreenMereologyTask (computing)View (database)Electronic mailing listMessage passingDescriptive statisticsOperator (mathematics)Phase transitionSystem callMedical imagingFlickrDirected graphPoint (geometry)Multiplication signEndliche ModelltheorieFigurate numberMobile appDigital photographyWeb pageRevision controlStatisticsResultantCASE <Informatik>Calculation40 (number)Form (programming)WindowInterface (computing)Social classCountingThread (computing)Goodness of fitFront and back endsData storage deviceComputer animationPanel painting
50:30
Template (C++)Element (mathematics)ImplementationMedical imagingTemplate (C++)GradientMereologyVirtualizationCASE <Informatik>Event horizonElement (mathematics)TouchscreenDreizehnAddress spaceElectronic visual displayMoment (mathematics)View (database)Content (media)Structural load2 (number)CodeInheritance (object-oriented programming)Computer animation
52:23
Simultaneous localization and mappingDemo (music)Template (C++)TouchscreenInternetworkingLogic gateSound effectBitTemplate (C++)Medical imagingComputer animation
53:22
Chemical equationNormed vector spaceMenu (computing)Execution unitInclusion mapGamma functionOvalUsabilityMIDIHost Identity ProtocolSmith chartComputer-generated imageryCAN busView (database)Maxima and minimaInterior (topology)Sign (mathematics)SummierbarkeitTemplate (C++)Ordinary differential equationImplementationHand fanSoftware design patternBitCodeLogical constantNeuroinformatik2 (number)Parameter (computer programming)RoutingEvent horizonMedical imagingMultiplication signSystem callElement (mathematics)Template (C++)Data miningSlide rule1 (number)Content (media)CASE <Informatik>Pattern languageBoss CorporationProjective planeSource codeBlock (periodic table)View (database)Control flowTraverse (surveying)RootMathematicsComputer animation
57:00
Interior (topology)Royal NavyGamma functionVirtualizationDirected graphStatement (computer science)State of matterCodeTask (computing)WeightMultiplication signDemosceneTouchscreenSound effectFile systemWindowThread (computing)Function (mathematics)View (database)Complete metric spaceComputer animation
59:29
Demo (music)Maxima and minimaLink (knot theory)Video game consoleThread (computing)CodeWindowTask (computing)Right angleComputer animation
01:00:34
Demo (music)GeometryoutputBlogHypermediaInstallable File SystemRight angleNumberThread (computing)Multiplication signSlide ruleFile systemLatent heatData storage deviceMobile appWindowCartesian coordinate systemBlog1 (number)Semiconductor memoryProfil (magazine)VirtualizationCASE <Informatik>Video gameCycle (graph theory)HypermediaIndependence (probability theory)Computer animation
01:02:32
Computer animation
Transcript: English(auto-generated)
00:03
Okay, everyone can hear me, I guess? Okay, our last session of the last day of a great conference, so I'm very glad some people decided to stay until the end, and I hope I'll make it work for a while. I'm going to start by introducing myself.
00:20
My name is Kevin. I'm a solution architect, mainly focusing on mobile applications. I've been at the same company, Real Dolmen, a Belgian company, for about 10 years. So the things I'm currently doing, it's mainly backend stuff, so mainly architecture stuff, so we can make applications cross-platform for mobile clients.
00:44
One of those mobile clients we tend to make is a Windows Store app, or a Windows Phone app even. And when you think about Windows Phone app, Windows Store app, that's XAML in my case, then what we often see are problems with performance, even now. So that's what this session is about.
01:02
It's really about tips and tricks to make your app perform great. If you want to reach me afterwards, my email address is on there. That's my personal email address, but the easiest by far is Twitter. So that's the easiest way to reach me. Okay, so let's have a look at what we're going to look at today.
01:23
I'm going to start with XAML Architecture Overview, because it's quite important to know what's going on behind the scenes, so we can understand what we need to do to get our app performing well. So that's the first thing. And then we're going to dive right into some XAML performance tips and tricks.
01:41
By this I mean these are the tips and tricks on how to organize your XAML, how to write the XAML elements to ensure that performance is great, and what writing them wrongly can have as an impact. Now, if we're talking about performance, we also need a way to measure this. And there's a few ways of analyzing performance.
02:03
It's mainly memory analyzation, by the way, not performance profilers. And in this part I'm going to look into the built-in stuff, and during the session we'll also look into another way of analyzing performance, which is even more useful than what's built in. Now we'll look into some resource dictionary strategies.
02:23
It's a very small part, but it's pretty important because doing this wrongly can definitely have quite an impact on performance, specifically startup performance. After that, it's probably the most interesting part of the talk and the longest. It's UI virtualization, data virtualization,
02:42
and a new feature in Windows Store Apps 8.1, incremental data templates. If you do UI virtualization right and data virtualization right, then you have huge performance wins. So those are pretty important. And then I'd like to end with one slide and one demo on tasks, threats, and offloading,
03:04
mainly the number one mistake we see people make that can have a dramatic impact on performance, a dramatic negative impact on performance even. But let's start with that architecture stuff, right? I'm just going to put the slide on screen. It's a bit easier to explain.
03:21
So first of all, the architecture by default is multi-threaded. So XAML and the underlying .NET framework you use, or WinRT in this case, which has really very little to do with the .NET framework, is multi-threaded by default. So you don't have to do anything for this. If you have multiple cores,
03:41
the XAML framework will automatically distribute the work across those. Nothing needed there, but it's interesting to know, right? And then you see three types of threats on screen here. The UI threat, the composition threat, and the worker threats. The worker threats are the easiest. That's the stuff we do ourselves, at least if we offload it to another threat.
04:00
So our user code, if we offload it to the background, and application code, if it's offloaded to the background, runs on separate worker threats. The UI threat and the composition threat, on the other hand, those are there all the time. And the responsibilities immediately give away what we need to take care of and think of performance.
04:21
So they run in sync, and the UI threat is the most heavy one. It's responsible at first for parsing all your XAML. So that's quite heavy stuff. It needs to parse those files. It's also responsible for taking those XAML elements, having a layout pass run on them, and then rendering them to visual primitives, let's say.
04:42
And it then hands over those visual primitives to the composition threat, and the main responsibility of the composition threat is sending drawing commands to your hardware to draw those things on screen. So the UI threat actually parses and renders everything, and that's quite heavy. And then it hands it off to the composition threat,
05:01
and that just composes the scene and sends it to the hardware. So far, so good. That's still not too heavy. But if you go and look into what other responsibilities the UI threat has, then you can immediately see that there can be some problems with that, because the other responsibilities of the UI threat are handling events,
05:21
so button click events handled by the UI threat, but also, by default, all your user code and all application code actually runs on your UI threat, unless you do something about it. So if you have a button click and you write code in there, that's actually running on your UI threat. If you write a very heavy algorithm,
05:42
some calculations in there, it's running on your UI threat. All application code as well. This may sound a bit weird, but I actually have some proof of that near the end of the session. So in fact, the thing we want to do is offload this UI threat as much as possible. And you can do that in two ways,
06:01
either by ensuring code runs on the composition threat, which is pretty lightweight. There's room enough there, typically. Or by ensuring it runs into another threat, one of those worker threats. Now, how can you do that? How can you offload stuff from the UI threat to your composition threat?
06:20
You can't just say, hey, CPU, run this on the composition threat. You can't do that. What you can do is organize your XAML in such a way that it automatically runs on the composition threat. And one of the ways of doing that is using independent instead of dependent animations.
06:41
That's a huge win. An independent animation is an animation that has no impact on other objects in the scene. A dependent animation is one that when you animate a button, for example, that can have an impact on the position of other stuff on the same page. That automatically gets handed over to the composition threat,
07:01
and the composition threat also takes care of scrolling and panning. So it does that by default. But all the other stuff is up to us. And that's what this session is about, really. It's all about offloading stuff from your UI threat. Both UI virtualization, data virtualization, almost everything.
07:21
Okay, so with that in the back of our heads, we can start with a few XAML tips and tricks. First thing, you should always optimize your element count. If you look at something like this, this code will result in a black screen, right? A grid and a rectangle fill color black. But these are two elements.
07:40
We've now created a grid in memory and a rectangle in memory. This is a better way of writing this. It's exactly the same result, but you only have one element in man. Now, it's very small impact, but imagine this, stuff like this in a grid view data template with tens of thousands of items.
08:01
Well, then you can see how this can start piling up. Another one is same type of stuff, so getting your memory load as low as possible. The brushes you define as a static resource, they are created once and reused. On the other hand, if you define a brush at property level, it isn't reused.
08:21
It's created every time over and over again. So if you look at code like this, we have a text box here. Foreground color is the same as that button's foreground color. That actually results in two brushes being created in memory, so two solid color brush instances. While on the other hand, if you define that brush
08:42
as a static resource in your resource dictionary and then reference it like this, there's only one instance of that. So that helps keep memory usage low as well. Now, I'm talking about memory you should always try and keep in the back of your head that you're not working
09:02
and you're not designing and creating an app for a machine like this. This is a developer machine. All your machines are developer machines, but we're creating applications that should run smoothly on very low-end, and that's typically ARM, very low-end ARM devices. They don't have the memory we have.
09:21
They don't have the GPUs we have. That's what we always need to keep in the back of our heads. And while on that subject, there's one thing that's really important there, and that's this one. We should always minimize redrawing, and what that means is if I write code like this,
09:41
I have a grid with two rows, background black, and on the second row, we have white with opacity 0.5. So this will result in a screen that's half black, half see-through white, something like that. What happens when this is sent to the composition thread
10:01
and then to the drawing hardware is at first the complete screen is drawn in black, and then it's overdrawn, half of it, in, well, gray this will be then. The problem is that it's drawing two pixels in the same place. If you do it like this, we don't have that anymore.
10:21
We're not drawing two pixels in the same place anymore. And why is this so important? Well, a low-end ARM device can take about four pixels in the same place before starting to stutter. And four pixels in the same place, it's really not a lot. That's an app with a background on that grid view with some items with their own background, that's two pixels.
10:44
On top of that, an image maybe, that's three pixels, and maybe you want some text on top of that, that's four pixels already. So this actually trumps everything. If you need to choose between creating more elements, like in this case two rectangles, which kind of goes against what I said in the beginning,
11:02
or overdrawing, then you should always choose for this. And I'm immediately going to show you the impact of it as well. So that's the most important one because low-end devices are not very good at handling overdraw. So how can we measure this then? Well, there's two things that are built into the framework
11:23
that we can use. The first one is the frame rate counter. So we can just use debugSettings.enableFrameRateCounter, typically in your app startup. And then you get something like this on the left of your screen, on the right of your screen. And what do these numbers mean? I'm just going to put it all on screen.
11:42
There we go. So the first one tells me what my UI thread frame rate is. And the second one tells me the CPU usage that's used per frame on the UI thread. The two last numbers, that's composition engine, system-wide, by the way, and composition engine CPU usage.
12:02
If you look at this, what would you want to use most? Because it's a bit counterintuitive. Probably, let's say, the app frames per second. Everything on my UI thread. I want to look at what's going on on my UI thread.
12:21
Well, the thing is, if something's wrong on your UI threads, you are probably having problems with not offloading stuff to the background through tasks or not using UI virtualization. And those two topics will come after this. And there are better ways to analyze that, which I'll also show.
12:40
So what I tend to use this for is to look at overdraw, to look at how heavy my composition engine is being hit. So I tend to look at the fourth one on screen. The next thing you can use also for overdraw is overdraw heatmap. This is the app we will use throughout the demos.
13:02
It's a list of recipes, and if you enable the overdraw heatmap, you actually get something like this. The darker this is, the lighter, apparently, the lighter this is, the more pixels are drawn in the same place. So now let me show you what the effect of that overdraw can be.
13:22
I'm just going to... This is... Huh, wait. You don't see it yet. Let's try it like that. That's better. Okay, so I have...
13:41
Let me go down. Okay. Can everyone read that like this? So this is a grid view, and the grid view is bound to a list of recipes, and it, of course, has an item template. This one, regular recipe template, to show me, as you can see here, those recipes.
14:04
Now, I'm first going to show this to you with a very bad data template. So let me just uncomment that, and comment the good one out. I'm actually doing everything wrong here
14:23
because I am not reusing my brushes, as you can see. So this brush and this brush should all be the same static resource. I am overdrawing way too much. My grid's background, on top of that,
14:42
a border with inside the border, a rectangle that's overdrawn, overdrawn, overdraw, et cetera, et cetera, et cetera. So I'm actually going against everything I just said. Now, let's see what this gives. I already put the frame rate counters on when I run it.
15:01
Okay, so it's building. There we go. Look at the number at the top right of your screen. So I'm scrolling. It's around six. That's five, six, something like that.
15:22
That's not much. It's very smooth on my PC. Now, let's have a look at that other data template. So that's the composition engine that's in place here. So I can really use that for overdrawing and the effect of it
15:41
because each pixel that has to be drawn is sent to the composition engine and then to the hardware. This is a better template. It results in mostly the same, but there's less overdraw. There's a lot less elements there. I'm using resource, a static resource.
16:02
Now, let's have a look at the effect. And I'm going to scroll again. Now, it's around four all the time. So what we had previously was around six, I guess.
16:22
Now, around four. You don't see the difference on my machine, but what this means is that by simply ensuring that my XAML is written in a way that takes into account the overdraw and the element count, I've actually reached a 50% speed increase or a 50% less load on my composition thread.
16:41
That's actually a huge improvement simply by looking at your XAML code. And I said this is a development machine. I can't just make it slower, although I always want fast machines. Anyway, I can't just make it slower, but do this on an ARM tablet and you'll start noticing the difference.
17:01
Okay, so that's the impact of writing your XAML correctly. Now, let me start this up again. When talking about XAML and how it's structured,
17:23
there's a few things that aren't so obvious that you should also take into account. And the first one is that one of the things that can lead to huge improvement is the fact that a control has a default style. But more often than not, you're not using everything in that control. If you look at the template of a control, say a grid view item or any control actually,
17:45
you'll see it has a visual state manager to go from normal state to hover state to checked state, et cetera, et cetera, et cetera. All those states contain elements. And all those elements are created when an instance of that button, for example, is created,
18:02
even though you might never use the checked state or the hover state or et cetera, et cetera. If you don't use it, throw it out, because it's all elements that have to be created. And even then, if you do want to use all the states, well, the default states aren't always that very optimized.
18:21
So it's always a good idea to look at the default templates and remove what you don't need. One good thing, though, this was very important in Windows Store apps, Windows 8. Windows 8.1, Microsoft got pretty smart. They noticed some problems with list views and grid views.
18:41
And they actually improved performance of it through this here. Instead of, first of all, they optimized the default templates for those items. And second of all, and that's a very smart thing, they created separate presenters. So you don't have to do anything for this.
19:02
If you use a grid view now, there's a grid view item or list view item presenter. And what that will do is, instead of creating all the states at once for each item, it will only create those states at the moment the user actually uses them. So that's a pretty smart thing of them to do. And it helped performance tremendously.
19:22
Regardless of that, still a good idea to look into the different templates. We'll also look at some of the impacts of the grid view and templates later on, especially during the UI virtualization stuff. Okay, so then we have the resource dictionary strategies.
19:43
And this is also interesting to know. Everything you put in a resource dictionary is parsed at the moment that resource dictionary is referenced. So what we see a lot is that people think, okay, great, I'm going to put my resources in a resource dictionary, not on that page. That's not very nicely ordered.
20:01
No, I'm going to put in a resource dictionary. And you end up with a huge resource dictionary. And that resource dictionary is then referenced in your app.saml. That means that when your application starts, the full resource dictionary has to be parsed. And as you probably know, resource dictionary can grow to a huge amount of resources after a while.
20:22
But that really doesn't make sense to do it like this. This really hurts startup performance. Why would you parse all the resources even though some of those resources might only be used on one page or on two or three pages? So the general idea is the resource dictionary
20:42
you reference in your app.saml should only contain application-wide resources like brushes that are used throughout the app. It should never contain stuff like data templates that's only used on one page or on a few pages. For that, you can either use the pages resource dictionary, so page.resources, that's made for that.
21:01
Or you can use a resource dictionary that you only import on the pages that actually use those resources. Just don't put them in one huge resource dictionary because it will definitely hurt startup performance. There is a trade-off, however. If you don't cache your page,
21:22
the resources that you put on page level will have to be parsed every time the user goes to that page again. So this is not something I can say as a general rule. It's something that you'll have to look into on a page-per-page basis or application-per-application basis. What I tend to do is ensure my pages are cached, always.
21:43
And I never put page resources in the application-wide resource dictionary. And that actually really helps just because parsing is way too expensive and slows stuff down. Okay, on to UI virtualization. What is UI virtualization?
22:02
Well, imagine you have a huge list of recipes in my case. It's about 1,000, I think. And those recipes are already in memory. So we're talking about UI here, not about data. That's what's coming up next. So 1,000 recipes, recipe objects in memory.
22:22
If you don't have UI virtualization and you bind that list of 1,000 recipes to your grid view, all those 1,000 item containers with all their images and all their overlays, et cetera, will be created, even though there might be only 20 on screen at a time.
22:41
That has a huge impact, right? All those containers have to be created. Everything has to be parsed. Everything has to be rendered, layout, passes, all on your UI thread. It will be slow. UI virtualization, however, ensures that while the data is still in memory, of course, the item containers will only be created
23:01
once the item is almost ready to be shown on screen. So instead of 1,000 recipes of recipe item containers, I'll have about 50 or 60. So it does some prefetching and stuff like that. But it won't be 1,000. It will be 50 or 60.
23:21
This is a huge performance win, by the way. Now, how do you get it? Well, that's the great news. If you don't do anything wrong, you get it out of the box. So every item control that derives from items control,
23:40
like a list view, grid view, even your own custom item controls, they support UI virtualization out of the box. So that's pretty great, right? Well, the problem is that there's quite a few things that can disable UI virtualization if you're not careful.
24:01
One of those things, the items panel. A grid view or a list view has a default items panel. Since Windows Store apps 8.1, it's the item wrap grid by default. That supports UI virtualization. But if you change that panel, you must ensure you change it to one that still supports UI virtualization
24:23
because, for example, a stack panel or a variable-sized wrap grid, those don't support UI virtualization anymore. So if you use a variable-sized wrap grid, no UI virtualization. And there's actually nothing to be done about that currently. Another thing that disables UI virtualization,
24:41
or rather it used to disable it, was grouping. Once you start working with grouped data in Windows Store apps, what happened then was that the groups were virtualized, but the data inside of the groups wasn't. So imagine you have a thousand recipes and you divide them into three groups. What used to happen was all the items in group one would have to be rendered,
25:06
while group two and three maybe not. But all the items in group one, which may be 300, would have to be rendered because virtualization was on the group level. Windows 8.1 solved that. So now it's on items level, so you don't have to be afraid to use grouping anymore.
25:21
Another thing that, well, of course, you do need to use the item wrap grid or item stack panel. That's the two panels who support that with grouping. Another thing that destroys UI virtualization are data template selectors. So once you use a data template selector, no UI virtualization anymore.
25:42
Instead of data template selectors, it's not really good class design, but something, if performance really is a problem and you do need different data templates, what I see happening from time to time is one data template that actually contains two grids
26:00
and the underlying class contains a type property and you bind the grid you want to see to the specific type of data in your code behind, in your class. It's not great, but it often helps performance if you do need different data templates.
26:22
Now there's one more thing that's probably the most hard to fix or find out, but I'm first going to show a demo of this because when we talk about UI virtualization, you probably want to know how you can see if it's virtualized or not, right?
26:41
As I said, you can try and see, wow, this is too slow. Maybe it's not virtualized, but that's not really correct, right? So let's try that. Now you do that, well, you actually need a memory profiler for that, right?
27:00
The thing is what we're going to do is we're going to check how many of those grid view items, let's say, are created in memory. And by analyzing our memory, we can then see, whoa, wait, this is about 1,000. That means UI virtualization isn't done. It's about the same as my amount of recipes that can't be good.
27:21
If it's a lot lower, you can say, okay, well, now I have UI virtualization. So I'm going to start by using a panel that disables UI virtualization. As I said, variable sized wrap grid does that. There we go.
27:41
And I'm going to start a memory profiler. Now, I tend to use the Telerik tools. This is memory profiling from Telerik. But there's actually lots and lots of different vendors who all have their own tools. I used JetBrains once.
28:01
There's others as well. Well, they're all more or less the same, so it's really up to your own preference. I just like this one. But even if you want to use another tool or another vendor's memory profiler, well, the end result is the same. What you need to look at is the same. Okay, so let me start that up.
28:25
There we go. So I'm just going to let this start, and I'm not going to scroll or anything.
28:48
You might have already noticed that this was a little bit slower than in the beginning. The images appeared a bit slower. So you could already start guessing that something's wrong. But, well, it's better to really see it.
29:00
So these are my recipes, like about 10, 12 on screen. So let's say including prefetching. I'm not sure how many we'll get. But we sure shouldn't get a thousand of those, right? Okay, so I'm going to take a snapshot. And what you now want to look for is the types, the type instances that are in memory.
29:28
So let me make this a little bit bigger. So I can look by type here. What I expect to find are about a thousand recipe instances. That's normal. That's my data. Let me just order by instance.
29:42
It's probably the easiest to see. And there's about 936 items in here. Okay, that makes sense. Now what do I need to look for now to see if this UI virtualization is on or not? And that's where it starts to get a little bit annoying.
30:01
Because in Windows 8 apps, Windows Store 8, this was very easy. You just look for the grid view items. Because each item in that grid view, well, there's a grid view item instance. When I started preparing this demo for Windows Store 8.1 apps, I was amazed. Whoa, wait, where are my grid view items?
30:21
Then I started thinking about what I just said before. So Microsoft really improved grid view performance by using a grid view item presenter. Which automatically, which is responsible for generating grid view items. So you're not going to find grid view items in memory anymore.
30:40
Instead you need to go and look for something else. Something that is created, something an instance of is created for each recipe. And in this case, you can actually see these three lines here. If you go and look at the source code, a little bit of reflection of a grid view items presenter.
31:00
You can see that it actually uses these dictionaries to keep references to what it has to create. So by looking at these three, you can start to analyze whether or not UI virtualization is on or not. If this is about the same as the items in your data collection, which in this case is the case,
31:25
well then you can be sure there's no UI virtualization. This should be a lot lower. There's about one default and then one for each grid view item container. So now we have a 937, so that's definitely no UI virtualization.
31:41
Now let me start by changing this to a grid that is supportive of, to a panel that does support virtualization. Items grid, items wrap grid, that was it.
32:03
Okay, so here we are again. Now let me just do that again. If you look at how fast it will appear, how fast recipes will appear, it should become obvious that we now have UI virtualization.
32:29
That was already a bit faster. If I now go look at exactly the same, so let me get a snapshot. GetSnapshot takes a memory snapshot.
32:42
It dumps everything that's in memory at that certain time to the Telerik Just Trace so that it can analyze the memory. You can take different snapshots at different times as well if you want to look at what happens at that time and that time and compare them. So it's actually a memory dump.
33:03
And again I look at types, look at the instances. Let's see, 936 recipe instances. That's correct, that's my data. If I look at the same as I used to look at before, well we see we now have about 63.
33:21
So no longer are those created for everything that's not on screen. It's only created for what's on screen and some prefetching. So now we actually have UI virtualization. So that's a way of analyzing this. It's really all about memory analyzation. Now I said there was one more thing that can destroy UI virtualization.
33:47
Pretty important one as well. And that's the parent container. So for that we need to know what a viewport is. And a viewport, well that's the area of an items control that displays content.
34:03
So in fact in our case what's on screen, to put it easy. And when you have UI virtualization what actually happens is that only the items close to that viewport will have their containers created. The problem is if you put your items control, your grid view, in a parent that does not restrict viewport,
34:24
well then you won't have UI virtualization at all. So UI virtualization is only enabled when the parent container restricts the viewport. Now what restricts the viewport? A grid. A grid restricts the viewport. You can give it a height or a width, but even if this is your outer grid, so the root visual of your application,
34:46
then it will have a height and a width of your screen. So it's still restricted and that's okay. This will have UI virtualization. So that'll look like that. However, some parents disable UI virtualization.
35:04
And one of those is a canvas. So if you put your grid view in a canvas you won't have UI virtualization unless you specifically restrict the grid view itself. So restricting the width of the surrounding canvas or the surrounding parent does not have an effect.
35:23
You must restrict the width of the items control bound to the list you want to see virtualized. I'm going to show you this.
35:44
Let's see. Like that. So what I'm going to do now is I'm just going to put that same grid view in a canvas. There we go.
36:05
And let me just comment this out. So I have a grid view here. Even though the canvas has a set width and height, the grid view hasn't.
36:21
Items reference, so I should have UI virtualization. Let me start that up.
36:43
And if everything goes as planned, this won't look good because it's in a canvas so it's going to go down. There we go. You see it's slow already. And if I now take another snapshot, let's take one.
37:01
And I'm just going to do exactly the same as I did before. Instances. And there we go. Again, the same high amount we really don't need. So UI virtualization is disabled. I can enable that again by setting a fixed width and height on the grid view.
37:22
Now you might think, who in some good sense is going to put a grid view in a canvas, right? The problem is there's another one, another control that disables it that doesn't restrict the viewport and that's a scroll viewer. So if you have your grid view in a scroll viewer, no UI virtualization.
37:42
And it goes even further than that because often you are making pages that are then shown somewhere on another page. Well, the parent just goes up and up. So if somewhere on that other page there's a scroll viewer and inside that scroll viewer the width isn't restricted on the grid view, you will not have UI virtualization.
38:04
So the importance of the parent container, that's one of the main mistakes we see made that disables UI virtualization. Okay, so after UI virtualization, there's data virtualization.
38:23
And when we talk about data virtualization, it's actually paging. That's the nice way to put it. So instead of working with that list of a thousand recipes or 936 apparently, we only work with a subset of the data instead of all the data.
38:40
So we're going to go and load the data on demand. If you combine this with UI virtualization, well, that's pretty much a huge performance win. And there's two types of data virtualization supported by Windows Store apps. One is random access virtualization and the other one is incremental virtualization. And we're going to look into both.
39:00
First one, random access virtualization. What this means is this is used when you know the amount of, and I'm just going to say recipes because that's what we'll keep on using. If you know the amount of recipes that will be in your collection beforehand, but you do not want to load all of them at once. So you know there'll be about a thousand recipes, but you only want to load, let's say, 20 recipes when the user scrolls to a specific position.
39:26
So when the user scrolls to position 20, recipe 20 to 40 is loaded. When he scrolls to position 100, 100 to 120 is loaded. This is just only applicable for cases where you know the amount of items you will have in advance.
39:44
And to do that and to do any kind of data virtualization, actually, you're going to have to make your own collection type. What does this mean? Well, for random data access virtualization, you just need to implement inotify collection, property collection changed, inotify collection changed, and inotify property changed.
40:06
Your collection is then responsible for fetching the data async. And the general idea is when the data hasn't been fetched, you just return nll, which will then show the placeholder. When the data must be fetched, you will load it async, you will put it in the collection's internal collection,
40:24
and you will notify the UI that a certain element at a certain position has been replaced. And I'm going to show you how it looks and how to do it. Okay. So back to our solution.
40:42
This just keeps on switching between duplicate and extend, so I have to switch as well. Okay, so I turned off the memory profiler. That's good. And first I'm going to show you what it looks like. I just created a list with the same recipe over and over and over again.
41:03
Now, of course, the thing to know is I'm doing this from my PC, so I kind of faked a little delay so you could see what's going on. This one was the previous one. I think it's this. Noob. This.
41:22
So I have a list here, lots of times the same recipe. As you can see below here, scroll bar, it already knows that there are more. If I now go, say, a bit further, you can see there's no recipes there yet, and they are fetched on demand.
41:41
So I scroll somewhere, nothing there. Those are all the placeholders, the gray stuff. And then somehow they get fetched and they get shown. So that's what random data access virtualization is. Now let's look at how we do that. Well, actually, it's just a grid view bound to a recipe collection, but I'm going to show you the collection it's bound to.
42:05
It's a collection I named Random Access Virtualization, a recipe collection. Now let's look at how we implement that. I just implemented the iList interface and iNotify collection changed.
42:21
Now there's a lot of plumbing going on here, but I'm going to focus on the important part. I do put the code on my blog later on, so you'll have it anyway. How does it know what to fetch and how do we fetch it? Those are the two important parts. Well, if you bind a list, any list actually, to a grid view, it's going to load items.
42:45
When you scroll to a certain position, it's going to trigger the indexer. So that's what we get out of the box. That means we get this. This is the indexer and it passes in the position it needs to get.
43:00
If you bind this to a list that's fully loaded, well, the indexer will just get the correct item out of the internal collection and show it. In our case, we don't have that yet because it's all annual out first. So we need to fetch it. That means that in the getter, we need to, and I'm just going to focus on the important parts here, we need to start loading the items.
43:25
There's a bit of plumbing in here that ensures the items aren't loaded too much. The important part here is that the first thing we do is ensure we return NULL, which shows the placeholder. And as this is async, so NULL is returned before this is done.
43:47
So the placeholder is shown. And then we load a bunch of items. And the important part is here again. That's it.
44:00
So we run through, and again, this is plumbing, so I can load 20 items at the same time. I fake some delay because this will typically go to your backend. I get back the recipe I need. And I put it in the internal dictionary. So now my iList implementation's internal dictionary contains that item, so next
44:21
time it's fetched, it will automatically get that out of the internal dictionary. And then the last thing I need to do is raise property changed on that item. And that's then what happens here. It's a simple notify collection changed. It says that item has been replaced.
44:42
And that's actually all there is to it. If you look at it, it's not a lot of code. A lot of this is plumbing, just to ensure I have a stack that not too much is done over and over and over again. For the rest, there's not that much to it. So it's really pretty easy to get something like this. And this is pretty powerful even.
45:03
But there's another one that might be more suited depending on your scenario. And that's incremental virtualization. Random access virtualization was I know the amount of items I have and I want to load them on demand.
45:22
Incremental virtualization means I don't know the amount of items I'll have. But when the user scrolls to the end of my grid view, I want to load the rest of the items. And how you do that is by having a collection that implements I support incremental loading.
45:41
So that's the interface you need to implement. So typically you just create a collection that inherits observable collection and implement that interface. So let's look at that. I'm going to show you what it looks like first. I still have that open here.
46:01
I think it's this one. I have too many demos here. This is an incremental load. This is a collection that implemented I support incremental loading. And look at below here. Apparently about 20 items have been loaded. But when I start scrolling, it's automatically starting to load more, showing them on screen.
46:26
My collection gets bigger and so on and so on and so on. This actually just calls the Flickr API and I look for food or something. So let's look at that.
46:44
Oh, we're still there. Great. So, not much to see there. The view model just contains a recipe collection. This time I named Flickr collection with incremental load support.
47:02
Some plumbing here as well. So I actually have, where is it? A lot of this stuff is just to ensure I can call the backend Flickr API. So I created a photo data common class which holds the data I get back from Flickr API.
47:24
Just a title, owner, description, image, etc. And then I have my collection. So it should implement this interface. And if I look at what this interface has, well, it's not that much.
47:40
One, has more items. And two, an operation that is triggered when I reach the end of my screen by scrolling. Has more items kind of depends on what you're doing. But in this case I'm calling the Flickr API and I'm assuming there's going to be lots and lots of items.
48:02
So just for demo purposes I return true on has more items. Important thing here is the load more items async part. I somehow needed to return an iAsync operation. And I also know that I want to run this in the background. And I also know that running stuff in the background is with a task.
48:23
And I somehow need to cast that task to the iAsync operation. And it needs to have a generically typed load more items result in it. So that's a lot of stuff actually. The good thing is you can easily cast a task, which is this, to an async operation just calling .sasyncoperation.
48:45
Easy as that. That's good enough. And then I still need to know what this load more items result must contain. And actually that's just a helper class that contains the current count. So that's easy as well, right?
49:00
Then there's the loading. And what I do is I start a new task. And I pass in... Oh, I'm still running. I'm not going to do that. I pass in an async method to actually call the Flickr API. The Flickr API is called in this get page method. This is just a rest call, as you can see, which generally turns me a list of photos.
49:27
So I have these photos in this result. What do I need to do then? I need to add them to the collection. So that's this.add. And I have to do that through the dispatcher because the adding to the collection has to be done on the UI thread.
49:43
So I have to dispatch back to my UI thread. I'm specifically doing it like this. You don't have to do it like this with all this task, etc., etc. But if you don't do it like this, all the fetching will also... and all the calculations will also run on your UI thread. And that's what we want to avoid. So that's why I'm starting a task here.
50:02
I run the dispatcher. I add all the items to the internal collection. I increase the current page. It's just used for internal purposes. And I return the amount of items I got because that's what's expected by my interface. And with that code, I'm actually done. This is all I need to do to get incremental load support.
50:25
Now, there was something new introduced in Windows Store apps 8.1. There we go again. And that was incremental data templates. So at the moment, we already know about UI virtualization and data virtualization.
50:44
Well, here's a third thing that might help in some cases, some specific cases. And we're now talking about one recipe data template. So as you could see, those recipes are loaded at once. So data in there, the image is loaded, the image text is loaded,
51:03
and then it's pushed to composition and shown. What incremental data templates do is they allow us to load a specific part of the template first and display that and only afterwards display another part. So that could mean that I could already show all the text of the recipes,
51:24
so the name of the recipe, and load the image afterwards. Actually, it will never improve your performance. It will actually slow down your performance, but it will improve the perception of performance your user has because you already see something on screen
51:42
and he doesn't have to wait for both the text and image to be loaded. He only has to wait for the text and then the image will come afterwards. So this allows us to incrementally show elements from a data template instead of all at once. And how do you do that? Well, there's a new event. You handle the container content changing on ListViewBase,
52:03
and ListViewBase is the base class for GridView and ListView. And from there, you just go and look at what you want to show first and then pass that in and then register a method for the second pass, register a method for the third pass, and so on and so on.
52:20
There's quite a lot of code. I'm going to show you how it's done. Let me first show you what the effect is. If this is slow enough, it will work. It's not slow enough. I'm going to scroll, and if you look carefully...
52:41
Oh, screen gone. Duplicate. Ah, yeah, that's better. Okay, so this is using the incremental collection from before, laid out a little bit differently, and data templates that are incremental as well.
53:01
So if I go fast enough, you see it already. So first, the text is shown if text is available, and only afterwards the image is loaded. So this does give the user the perception that it's going faster, which can definitely help, so he already sees part of data.
53:21
Now, how do you do that? This has to be done in code behind, by the way. I'm not a very big fan of it, but it does work. Sometimes for performance, you kind of have to throw out best practices as far as design patterns are concerned.
53:45
So it's a bit of a trade-off. Let me show you that. Ah, that's not it. It's the third one, I think. This one.
54:02
I, of course, have to find it. Oh, here we go. So first, the XAML code. It's actually very little to do with XAML. The one thing you see here, my grid view with recipes, it has the container content changing event handled.
54:21
In code behind. What happens then? That's what I do. So I get in this content container changing. It will be triggered. This is the first pass, so it should be no. What I have to do then is I have to look at the arguments
54:41
which contain the item container, and that item container in turn contains the template root. So I actually have to go and traverse that to get to, in this case, first time, the text block that will show my recipe title. So that's the first thing I have to do, which is this code.
55:00
So I try to find all the elements in my data template. The ones I want to show, I set to visible. The ones I don't want to show yet. Opacity zero. And then I need to fill in the text of that title element. So that title text block. I always get the item passed in and the template itself.
55:24
So I can do everything I need with this. So from the arguments item, I get the underlying data. From the arguments item container, I get the data template. So what I do then is I set the title's text
55:40
to the title from the data. And then I need to register an update callback, which is the method that will be triggered after this method is done. So the second time, the second pass, is used for loading the image. And then I'm in the show recipe image method,
56:01
which again gets these container content changing event arguments. I find the picture in this case. That's the name I gave to the image. I set it to visible and I set the source. That's how you do this. Now you can immediately see this actually breaks data binding.
56:21
It's an anti-data binding pattern. So should we use it? Yeah, yes and no. It depends on what you think is more important. But for some cases, it does make sense. I mean, for the end user, it probably makes sense. If you're an architect or a project leads,
56:40
it probably doesn't make as much sense. So it kind of depends. Okay, so the last thing I want to show you is this one. I'm not going to show the slide again, because I have to be in code anyway.
57:03
And that's the most important thing, the one common mistake that's made often. Using async wait will not offload to a background thread. Never, ever. And that's a very important mistake that's often made. We often think that, okay, well, I'm going to use async on my methods.
57:21
And in that method, I'm going to use await. So this will run on a background thread. Well, that's not true. If you don't do anything specifically, it will run on your UI thread. So the only thing the async keyword does is state, okay, this method can contain an await statement. And the only thing the await statement does is,
57:42
okay, run this code and return once it's completed. But if in the code that you're awaiting, you're not offloading anything to the background, then that will still run on the same thread you call it from, which is the UI thread. Then the next question is, why does this work for all those built-in API methods?
58:01
Because if you await a file system not open, well, it will run in the background. Well, that is because internally, Microsoft always starts up tasks. They start up new tasks, and if you start a new task, that will run in the background. So I'm going to show you this, because this is probably next to UI and data virtualization,
58:20
the most important thing you can do to offload stuff from your UI thread. And I'm just going to show you first how to not do it and what the effect is. I have a method here. Async returns a task.
58:42
But in that method, there's actually nothing offloaded to the background at all. So I could... If I use a task.run in here, this will be in the background. But this time, not doing it. I'm just writing out stuff to my output window.
59:00
And I do that once I click an item in my grid view. So let's see the effect of this. You probably know what's coming.
59:21
It's going to go bad. Okay, that's the second screen, I think. Okay, so I can nicely scroll. And I click, and you'll have to believe me now. I'm scrolling, but this doesn't work anymore. My UI hangs.
59:42
And why is my UI hanging? Because this code that's putting all this in my console window is now running on my UI threads, even though I'm using async await, et cetera, et cetera, et cetera. So how do you solve this then? Well, it's simple. You have to, for your own code, your user code, you have to manually start task.
01:00:00
to ensure it's scheduled on the background and no longer on your UI thread. So it's actually pretty easy. You can either do that in this method or you can do that here. And let me start that up again.
01:00:29
And if I now go and do the same thing, once it's loaded, there we go. To it was, I think, trans. I click and I can still nicely scroll even though it's outputting those same numbers.
01:00:47
So that's how you offload stuff from your UI thread. And it actually also proves that unless you do something about it, button click actually does run on your UI. Okay. So that was actually, except for the hidden slides, which I didn't want to show anyway.
01:01:03
So that's actually the last thing I wanted to show you. So I'm right on time, I guess. Now, is there more to be said about performance? Yes, of course there is. You might wonder why I'm not using a performance profile, but only memory profile. Performance profiling is something you typically do to profile how long a specific method takes, something like that.
01:01:24
While when you're working with XAML apps, your problems typically don't stem from that. They stem from bad UI virtualization, bad data virtualization. There's a lot of stuff to be said on working with animations, dependent or independent. There's a lot of best practices on working with media, the file system.
01:01:40
Application lifecycle is not one of those. It's too much to put in one hour. So I kind of picked out the ones that most mistakes are made against. If you want to know more about this, I'm going to put all these on my blog within a few hours. And there's actually a Pluralsight course I made on Windows Store app performance as well.
01:02:05
And I think if the guys are still there, they'll give you a free voucher for the Pluralsight course. So that's about all I had to say. If there are any questions, feel free to ask them.
01:02:21
No? Okay, so I thank you to stay till the end of the conference, the end of my session, and I hope it was useful. Thanks.