{"id":834,"date":"2019-06-24T19:35:00","date_gmt":"2019-06-24T19:35:00","guid":{"rendered":"https:\/\/staging.infragistics.com\/blogs\/?p=834"},"modified":"2025-02-18T13:53:25","modified_gmt":"2025-02-18T13:53:25","slug":"15-wpf-performance-tips","status":"publish","type":"post","link":"https:\/\/www.infragistics.com\/blogs\/15-wpf-performance-tips","title":{"rendered":"15 WPF Performance Tips"},"content":{"rendered":"\n<p>Are you a WPF developer? Do your WPF apps have areas of poor performance or don\u2019t run as quickly as you would like?&nbsp; If so, I have&nbsp;15<b>&nbsp;<\/b>tips to help you identify and improve the performance of your WPF applications.&nbsp;<\/p>\n\n\n\n<p>While WPF is over a decade old and has been improved greatly over the years, there are still&nbsp;several&nbsp;areas that can suffer from poor performance.&nbsp; The reasons for this poor performance&nbsp;include things such as&nbsp;bad&nbsp;coding practices, broken bindings, complex layouts, the lack of UI virtualization, and much more. Luckily, with a little planning and a solid understanding of the WPF platform, you can have your WPF apps jumping into warp speed and&nbsp;leaping&nbsp;across the universe in milliseconds.&nbsp;<\/p>\n\n\n\n<p>I have put together&nbsp;these&nbsp;15&nbsp;tips&nbsp;to&nbsp;help you improve the performance of your WPF apps.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"1-simplify-your-visual-tree\">1. Simplify your Visual Tree<\/h2>\n\n\n\n<p><span class=\"TextRun SCXW110082149 BCX0\" lang=\"EN-US\"><span class=\"NormalTextRun SCXW110082149 BCX0\">A common source of performance issues is a deep and complex layout. Keep your XAML markup as simple and shallow as possible.&nbsp;<\/span><\/span><span class=\"TextRun SCXW110082149 BCX0\" lang=\"EN-US\"><span class=\"NormalTextRun SCXW110082149 BCX0\">When UI elements are drawn onscreen, a \u201clayout pass\u201d is called twice for each element (a measure pass and an arrange pass). The<\/span><\/span><span class=\"TextRun SCXW110082149 BCX0\" lang=\"EN-US\"><span class=\"NormalTextRun SCXW110082149 BCX0\">&nbsp;layout pass is a mathematically-intensive process\u2014the larger the number of&nbsp;<\/span><\/span><span class=\"TextRun SCXW110082149 BCX0\" lang=\"EN-US\"><span class=\"NormalTextRun SCXW110082149 BCX0\">children<\/span><\/span><span class=\"TextRun SCXW110082149 BCX0\" lang=\"EN-US\"><span class=\"NormalTextRun SCXW110082149 BCX0\">&nbsp;in the&nbsp;<\/span><\/span><span class=\"TextRun SCXW110082149 BCX0\" lang=\"EN-US\"><span class=\"NormalTextRun SCXW110082149 BCX0\">element<\/span><\/span><span class=\"TextRun SCXW110082149 BCX0\" lang=\"EN-US\"><span class=\"NormalTextRun SCXW110082149 BCX0\">, the greater the number of calculations required<\/span><\/span><span class=\"TextRun SCXW110082149 BCX0\" lang=\"EN-US\"><span class=\"NormalTextRun SCXW110082149 BCX0\">.<\/span><\/span><span class=\"TextRun SCXW110082149 BCX0\" lang=\"EN-US\"><span class=\"NormalTextRun SCXW110082149 BCX0\">&nbsp;<\/span><\/span><span class=\"EOP SCXW110082149 BCX0\">&nbsp;<\/span><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"2-virtualize-your-itemscontrols\">2. Virtualize your ItemsControls<\/h2>\n\n\n\n<p><span class=\"EOP SCXW110082149 BCX0\">As mentioned&nbsp;earlier, a complex and deep visual tree results in a larger memory footprint and slower performance.&nbsp;ItemsControls&nbsp;usually increase performance problems with deep visual trees because they are not virtualized. This means they are constantly being created and destroyed for each item in the control. Instead,&nbsp;use the&nbsp;VirtualizingStackPanel&nbsp;as the items host and make use of the&nbsp;VirtualizingStackPanel.IsVirtualizing&nbsp;and set the&nbsp;VirtualizationMode&nbsp;to&nbsp;Recycling&nbsp;in order to reuse item containers instead of creating new ones each time.&nbsp;<br><\/span><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"3-favor-staticresources-over-dynamicresources\">3. Favor StaticResources over DynamicResources<\/h2>\n\n\n\n<p><span class=\"EOP SCXW110082149 BCX0\">StaticResources&nbsp;provide values&nbsp;for any XAML property attribute by looking up a reference to an already defined resource. Lookup behavior for that resource is&nbsp;the same as a&nbsp;compile-time lookup.&nbsp;DynamicResources&nbsp;will create a temporary expression and defer lookup for resources until the requested resource value is&nbsp;required. Lookup behavior for that resource is&nbsp;the same as a&nbsp;run-time lookup, which imposes a performance impact.&nbsp;Always use a&nbsp;StaticResource&nbsp;whenever possible.&nbsp;<br><\/span><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"4-opacity-on-brushes-instead-of-elements\">4. Opacity on Brushes Instead of Elements<\/h2>\n\n\n\n<p><span class=\"EOP SCXW110082149 BCX0\">If you use a Brush to set the Fill or Stroke of an element, it is better to set the Opacity on the Brush rather than setting the element\u2019s Opacity property. When you modify an element\u2019s Opacity property, it can cause WPF to create temporary surfaces which results in a performance hit.&nbsp;<br><\/span><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"5-avoid-using-run-to-set-text-properties\">5. Avoid Using Run to Set Text Properties<\/h2>\n\n\n\n<p><span class=\"EOP SCXW110082149 BCX0\">Avoid using Runs within a&nbsp;TextBlock&nbsp;as this results in a much higher performance intensive operation. If you are using a Run to set text properties, set those directly on the&nbsp;TextBlock&nbsp;instead.&nbsp;<br><\/span><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"6-favor-streamgeometries-over-pathgeometries\">6. Favor StreamGeometries over PathGeometries<\/h2>\n\n\n\n<p><span class=\"EOP SCXW110082149 BCX0\">The&nbsp;StreamGeometry&nbsp;object is a very light-weight alternative to a&nbsp;PathGeometry.&nbsp;StreamGeometry&nbsp;is optimized for handling many&nbsp;PathGeometry&nbsp;objects. It consumes less memory and performs much better when compared to using many&nbsp;PathGeometry&nbsp;objects.&nbsp;<br><\/span><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"7-use-reduced-image-sizes\">7. Use Reduced Image Sizes<\/h2>\n\n\n\n<p><span class=\"EOP SCXW110082149 BCX0\">If your app requires the display of smaller thumbnails, consider creating reduced-sized versions of your images. By default, WPF will load and decode your image to its full size. This can be the source of many performance problems if you are loading full images and scaling them down to thumbnail sizes in controls such as an&nbsp;ItemsControl. If possible, combine all images into a single image, such as a film strip composed of multiple images.&nbsp;<br><\/span><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"8-lower-the-bitmapscalingmode\">8. Lower the BitMapScalingMode<\/h2>\n\n\n\n<p><span class=\"EOP SCXW110082149 BCX0\">By&nbsp;default, WPF uses a&nbsp;high-quality image re-sampling algorithm&nbsp;that&nbsp;can sometimes consume system resources&nbsp;which results in&nbsp;frame rate&nbsp;degradation and&nbsp;causes&nbsp;animations to stutter. Instead, set the&nbsp;BitMapScalingMode&nbsp;to&nbsp;LowQuality&nbsp;to switch from a \u201cquality-optimized\u201d algorithm to a \u201cspeed-optimized\u201d algorithm.&nbsp;<br><\/span><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"9-use-and-freeze-freezables\">9. Use and Freeze Freezables<\/h2>\n\n\n\n<p><span class=\"EOP SCXW110082149 BCX0\">A Freezable is a special type of object that has two states: unfrozen and frozen.&nbsp;When you freeze an object&nbsp;such as a Brush or Geometry, it can no longer be modified.&nbsp;Freezing objects whenever possible improves the performance of your application and reduces its&nbsp;memory consumption.&nbsp;<br><\/span><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"10-fix-your-binding-errors\">10. Fix your Binding Errors<\/h2>\n\n\n\n<p><span class=\"EOP SCXW110082149 BCX0\">Binding errors are the most common type of performance problem in WPF apps.&nbsp;Every time a binding error occurs, your app takes a perf hit and as it tries to&nbsp;resolve&nbsp;the binding and writes the&nbsp;error out to the trace log. As you can imagine, the more binding&nbsp;errors&nbsp;you have the bigger the performance hit your app will take.&nbsp;Take the time to find and fix all your binding errors.&nbsp;Using a&nbsp;RelativeSource&nbsp;binding in&nbsp;DataTemplates&nbsp;is a major culprit in binding error&nbsp;as the binding is usually not resolved properly until the&nbsp;DataTempate&nbsp;has completed its initialization.&nbsp;Avoid using&nbsp;RelativeSource.FindAncestor&nbsp;at all costs.&nbsp;Instead,&nbsp;define an attached property and use&nbsp;property inheritance to push values down the visual tree instead of looking up the visual tree.&nbsp;<br><\/span><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"11-avoid-databinding-to-the-label-content-property\">11. Avoid Databinding to the Label.Content Property<\/h2>\n\n\n\n<p><span class=\"EOP SCXW110082149 BCX0\">If you are using a Label to data bind to a String property, this will result in poor performance. This is because each time the String source is updated, the old string object is discarded, and a new String is created. If the Content of the Label is simple text, replace it with a&nbsp;TextBlock&nbsp;and bind to the Text property instead.&nbsp;<br><\/span><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"12-bind-itemscontrols-to-ilist-instead-of-ienumerable\">12. Bind ItemsControls to IList instead of IEnumerable<\/h2>\n\n\n\n<p><span class=\"EOP SCXW110082149 BCX0\">When data binding an&nbsp;ItemsControl&nbsp;to an&nbsp;IEnumerable, WPF will create a wrapper of type&nbsp;IList&lt;T&gt; which negatively impacts performance with the creation of a second object. Instead, bind the&nbsp;ItemsControl&nbsp;directly to an&nbsp;IList&nbsp;to avoid the overhead of the wrapper object.&nbsp;<br><\/span><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"13-use-the-neutralresourceslanguage-attribute\">13. Use the NeutralResourcesLanguage Attribute<\/h2>\n\n\n\n<p><span class=\"EOP SCXW110082149 BCX0\">Use&nbsp;the&nbsp;NeutralResourcesLanguageAttribute&nbsp;to tell the&nbsp;ResourceManager&nbsp;what the neutral culture is and avoid unsuccessful&nbsp;satellite&nbsp;assembly lookups.&nbsp;<br><\/span><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"14-load-data-on-separate-threads\">14. Load&nbsp;Data on&nbsp;Separate&nbsp;Threads<\/h2>\n\n\n\n<p><span class=\"EOP SCXW110082149 BCX0\">A very common source of performance problems,&nbsp;UI freezes, and apps that stop responding&nbsp;is how you load your data. Make sure you are&nbsp;asynchronously&nbsp;loading your data on a separate thread as to not&nbsp;overload&nbsp;the UI thread. Loading data on the UI thread will result in very poor performance and an overall&nbsp;bad end-user experience.&nbsp;Multi-threading should be something every WPF developer is using in their applications.&nbsp;<br><\/span><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" class=\"wp-block-heading\" id=\"15-beware-of-memory-leaks\">15. Beware of Memory Leaks<\/h2>\n\n\n\n<p><span class=\"EOP SCXW110082149 BCX0\">Memory leaks are the number&nbsp;one&nbsp;cause of performance problems in most WPF applications.&nbsp; They are easy to&nbsp;have but&nbsp;can be difficult to find.&nbsp; For example,&nbsp;using the&nbsp;DependencyPropertyDescriptor.AddValueChanged&nbsp;can&nbsp;cause the WPF framework to take a strong reference to the source of the event that isn\u2019t removed until you&nbsp;manually&nbsp;call&nbsp;DependencyPropertyDescriptor.RemoveValueChanged.&nbsp;If your views or behaviors rely on&nbsp;events being raised from&nbsp;an&nbsp;object or&nbsp;ViewModel (such as&nbsp;INotifyPropertyChanged),&nbsp;subscribe to them weakly&nbsp;or make sure you are manually unsubscribing.&nbsp;Also, if you are binding to properties in a ViewModel which does not implement&nbsp;INotifyPropertyChanged, chances are you have a memory leak.&nbsp;<\/span><\/p>\n\n\n\n<p><span class=\"EOP SCXW110082149 BCX0\">Finally, a bonus tip. Sometimes when you have a performance problem it can be very difficult to identify what exactly is causing the issue. I suggest using an application performance profiler to help identify where these performance bottle necks are occurring in your code base. There are a lot of profiler options available to you. Some are paid, and some are free. The one I personally use the most is the <a href=\"https:\/\/docs.microsoft.com\/en-us\/visualstudio\/profiling\/profiling-feature-tour?view=vs-2019\" target=\"_blank\" rel=\"noopener noreferrer\">Diagnosis Tools <\/a>built directly into Visual Studio 2019.<\/span><\/p>\n\n\n\n<p><span class=\"EOP SCXW110082149 BCX0\">Be sure to engage with me on <a href=\"https:\/\/twitter.com\/brianlagunas\" target=\"_blank\" rel=\"noopener noreferrer\">Twitter<\/a>, subscribe to my <a href=\"https:\/\/www.youtube.com\/BrianLagunas\" target=\"_blank\" rel=\"noopener noreferrer\">YouTube channel<\/a> to be notified of new video content, and follow me on <a href=\"https:\/\/www.twitch.tv\/brianlagunas\" target=\"_blank\" rel=\"noopener noreferrer\">Twitch<\/a> to watch me stream live. And if you are using <a title=\"Ultimate UI for WPF\" href=\"\/products\/wpf\" target=\"_blank\" rel=\"noopener noreferrer\">Ultimate UI for WPF<\/a>, be sure to&nbsp;connect with our various teams via our&nbsp;<a class=\"mchNoDecorate\" href=\"\/community\/forums\" target=\"_blank\" rel=\"noopener noreferrer\">Community Forums<\/a>&nbsp;where you can interact with Infragistics engineers and other customers.&nbsp;&nbsp;<\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Are you a WPF developer? Here we present 15 tips to help you identify and improve the performance of your WPF applications. Read more.<\/p>\n","protected":false},"author":43,"featured_media":1150,"comment_status":"publish","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[14],"tags":[],"class_list":["post-834","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-wpf"],"_links":{"self":[{"href":"https:\/\/www.infragistics.com\/blogs\/wp-json\/wp\/v2\/posts\/834","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.infragistics.com\/blogs\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.infragistics.com\/blogs\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.infragistics.com\/blogs\/wp-json\/wp\/v2\/users\/43"}],"replies":[{"embeddable":true,"href":"https:\/\/www.infragistics.com\/blogs\/wp-json\/wp\/v2\/comments?post=834"}],"version-history":[{"count":14,"href":"https:\/\/www.infragistics.com\/blogs\/wp-json\/wp\/v2\/posts\/834\/revisions"}],"predecessor-version":[{"id":1878,"href":"https:\/\/www.infragistics.com\/blogs\/wp-json\/wp\/v2\/posts\/834\/revisions\/1878"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.infragistics.com\/blogs\/wp-json\/wp\/v2\/media\/1150"}],"wp:attachment":[{"href":"https:\/\/www.infragistics.com\/blogs\/wp-json\/wp\/v2\/media?parent=834"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.infragistics.com\/blogs\/wp-json\/wp\/v2\/categories?post=834"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.infragistics.com\/blogs\/wp-json\/wp\/v2\/tags?post=834"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}