Welcome to MSDN Blogs Sign in | Join | Help

.NET Framework 4 Client Profile - Introduction

Introduction

Hopefully folks have seen Soma’s and Jason Zander’s blogs announcing the availability of Beta 1 of Visual Studio 2010 and .NET Framework 4.
In .NET Framework 4 we introduced a streamlined subset and more compact version of the .NET Framework called the Microsoft .NET Framework 4 Client Profile. The goal of the Client Profile is to improve the deployment size, time, reliability and overall deployment experience for client application users.

The Client Profile contains the functionality that most common desktop client applications (including Windows Forms and WPF applications) would need, so we expect that many client application developers will use it. This will improve the overall application deployment experience when the application requires .NET Framework 4 to be installed.

One of the most important improvement is that Microsoft .NET Framework 4 Client Profile is now supporting all platforms and OS's that are supported by the full Framework including Vista, XP, Win2k3, Win2k8, Windows7, x86/x64 (excluding IA64)

We still expect some applications to target the full .NET Framework 4 if they need to use features that are not included in the .NET Framework 4 Client Profile.

Client Profile in Visual Studio 2010

Visual Studio 2008 introduced multitargeting for application projects to target 2.0 and 3.x versions of the .NET Framework. Visual Studio 2010 has improved multi-targeting in order to allow developers to easily target the new .NET Framework 4 Client Profile.

In Beta 1, when you create a new Windows Forms or WPF application, it targets the full framework by default. To change to targeting to the Client Profile, open the project properties, select the "Application" page, and change the “Target Framework” drop-down to “.NET Framework 4.0 Client Profile.”

C# project example:

image

VB project example (Project Properties > Compile tab > “Advanced Compile Options…”):

image

Notice that if you right-click the project and select “Add References…”, the dialog will show only the .NET Framework assemblies that are part of the Client Profile. This is accomplished by using reference assemblies, metadata-only versions of assemblies. The .NET Framework 4 Client Profile Reference Assemblies are located in

%programfiles%\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\Profile\Client

At compile time, the reference assemblies are matched up against the known "Client List" assemblies that are included in the Client Profile. If the project has a reference to a .NET assembly that is not included in the "Client List", Visual Studio will display compile-time errors in the Error List.

Similar to the .NET 3.5 Framework SP1 Client Profile, the project adds a configuration file (app.config) that will specifically declare the application as a "client" application. This declaration indicates to the CLR loader that you are trying to run a Client Profile application. Without the configuration file, the CLR loader thinks that you are trying to run full .NET 4, and if the machine only has the Client Profile installed, it prompts ebd-user to install the full .NET 4. [Note: this functionality is not available in Beta1.]

Enhancement in 4.0 Client Profile vs. 3.5 SP1 Client profile:

Although the concept of a Client Profile is not new and was introduced in .NET Framework 3.5 SP1, the 4.0 Client Profile contains important improvements:

 

.NET Framework 4 Client Profile

.NET Framework 3.5 SP1 Client Profile

Supported OS

Supported on all platforms and  OS's that are supported by the .NET Framework (excluding IA64 and Server Core role in W2K8)

Supported only on Windows XP 32-bit machines that did not have any .NET Framework version installed.

(Client Profile will install the full 3.5 SP1 Framework under the covers otherwise)

Redistributable

Supports redistributable as well as web download

Supports Web download only

Add Remove Programs entries

The full Framework comprises the Client Profile and another part called “Extended” thus it has two entries in the  Add Remove Programs dialog (or Programs and Features window).

To remove (or repair) the full Framework you must remove the Extended part first, then the Client part.

If you installed the full Framework, you can go to the Client Profile by removing “Extended” from Add/Remove Programs.

Single entry in Add Remove Programs

Visual Studio

Improved support for Client Profile targeting in Visual Studio 2010

 

Features

Includes new .NET 4  features (such as Managed Extensibility Framework (MEF), C# 4 Dynamic Keyword, etc)

 

What’s in and what’s not included in the Client Profile:

Features

full Framework

Client Profile

Common Language Runtime

   

Can be installed side-by-side with older versions of the Framework

In-process side by side support

Improved COM interop

     

Innovations in the Visual Basic and C# languages

   

statement lambdas

implicit line continuations

dynamic dispatch

named/optional parameters

     

Base Class Library Improvements

   

Managed Extensibility Framework

Additional core data structures

I/O Improvements

     

Parallel Computing Innovations

   

Task Parallel Library (TPL)

Parallel LINQ (PLINQ)

     

ADO.NET

   

REST-based exposure of relational data

Entity Framework, LINQ to Entities

SqlClient, OLEDB, ODBC Managed Providers

XML, LINQ to XML

OracleClient

 

LINQ to SQL

 

Runtime design libraries for Entity Framework and ADO.NET Data Services

 
     

ASP.NET Innovations

 
     

ASP.NET AJAX Improvements

 
     

XAML Parser

   

Faster

More extensibility during XamlReader.Load and XamlWriter.Save

Ability to use generics               

Better References by Name

     

Windows Communications Foundation

   

WCF Client Component

WCF Workflow Services

 

Service discovery

 

Router service

 

Simplified configuration

Improved queuing

REST support

Improved performance

     

Windows Presentation Foundation

   

New line-of-business controls including charting control, smart edit, data grid, and others that improve the experience for developers who build data centric applications

Support in for Windows 7 multi-touch, ribbon controls, and taskbar extensibility features

Added support in WPF for Surface 2.0 SDK

     

Windows Workflow Foundation

   

Improved activity programming model

 

Improved designer experience

 

New flowchart modeling style

 

Expanded activity palette

 

Workflow-rules integration

 

New message correlation features

 

Significant performance gains for WF-based workflows

 

Miscellaneous

 

 

Speech support

 

Various perf counters

 

MSBuild support

 

Visual Basic compiler and other compilers

 

• Full Support

Partial Support

 

Download and feedback

Please download the Client Profile from the download site here and provide us with feedback. We really would love to know:

  • What do you feel should be the size of the Client Profile?
  • Does it currently contain the right features set? What functionality is missing?
  • To reduce size, what functionality should be removed?
  • How easy it is to use in Visual Studio 2010?
  • Any other feedback?

Notes and caveats:

  • Redistributable package size for the Client Profile is not final (it is currently at ~34MB). Expect to see a smaller size by RTM. Web installer is also not supported in Beta 1
  • Note that the setup package file name includes the word “Client” vs. “Full” to differentiate between the two packages. (e.g. dotNetFx40_Client_x86.exe, dotNetFx40_Full_x86.exe)
  • Setup may require a reboot, depending on the OS and currently running programs during installation.
  • No bootstrapper package is available yet, so you will not find the .NET Framework 4 Client Profile in Visual Studio 2010's "Prerequisites" dialog in the project's "Publish" property tab.
  • We are still tweaking what should be included in Client Profile vs. full Framework, so it is very likely to change before RTM.
  • Support for the Client Profile Configuration Designer is not available in Beta 1 and likely will not be available before RTM.
Posted by jgoldb | 8 Comments

Great Charles Petzold post

Check out Charles Petzold blog.

It discusses and provide examples on how you in WPF you don’t need to re-create the entire render data just to handle property changes, and thus improve perf.

Posted by jgoldb | 0 Comments

Improving Microsoft DataGrid sorting performance - Part 3

As it was announced at the PDC 2008 keynote, the Microsoft WPF DataGrid V1 is now released and available with the WPF Toolkit on Codeplex.

I wanted to update my CustomSort sample to improve WPF DataGrid sort performance from here to use the released version of the WPF Toolkit.

Enjoy.

Posted by jgoldb | 1 Comments

Attachment(s): DataGridSort3.zip

Fixes to WpfPerf Performance Profiling Tool

Some folks reported issues with x64 & with x86 on non-US PCs with our first post.
On 10/9/2008 we posted an update.  These issues should be fixed now.

You are welcome to download from: http://windowsclient.net/wpf/perf/wpf-perf-tool.aspx

Posted by jgoldb | 3 Comments

ETW Event Tracing in WPF

Event Tracing for Windows (ETW) provides application developers the ability to start and stop event tracing sessions, instrument an application to provide trace events, and consume trace events.

In addition to Windows itself, WPF also emits an array of interesting events that can be used to track the execution of an application at the framework level.

Mike Cook wrote a great document that explain the various ETW events emitted by WPF.

Check out the this documentation here.

You are encouraged to use these events to measure and analyze your WPF application performance.

The WpfPerf tool for example, use these events extensively. In addition, the WPF team is also using ETW in its automated tests to analyze WPF performance and catch regressions.

Attached is also a sample that demonstrates how you can consume one of these events (UceNotifyPresent event) to measure frame-rate (aka FPS , Frame-per-Second) in a WPF application.

The sample animates a rectangle and outputs the FPS to a command window . It is writing to a command window and not to the main app window so that it will not affect the real FPS.
image 
You should expect to see frame-rate tied to the refresh rate of your monitor.
Special thanks to Mike Cook and  TJ Hsiang who helped put this sample together.

Posted by jgoldb | 6 Comments

Attachment(s): FPSMeasurementSample.zip

Updated WPFPerf Performance Profiling Tools for WPF

The WPFPerf tool comprises of a suite of performance profiling tools that allow you to analyze the run-time behavior of your WPF application and point to potential performance bottlenecks.

We now added some new functionality as well as given the tool a major facelift.
Below are highlights for some of the exciting improvements that are included in this update.
More details and download link is available here.
Most of the concepts on how to use the tool remain the same so you can still refer to the existing documentation for the tool here to learn more.  The tool should work on all 3.x version of .Net.

Note: some folks reported issues when installing on none-US machines. Until this is investigated, please install only on US  machine using the default local settings.

A) Much improved “Visual Profiler” tool:
image 

The Visual Profile tool now provides:

1) Search: provides the ability to search element in the application’s Element Tree.
image

2) Hotpath: Allows you to Right Click / Expand Hotpath on an Element Tree, the tree will expand to show the element in the sub-tree that consumes the most amount of CPU in that sub-tree.

3) Elements CPU Usage: As user expands the Element Tree (e.g. by using the Hotpath feature from above), elements that (Exclusively) consumes CPU time are highlighted in Red. The intensity of the Red highlighting corresponds to the percentage of CPU usage.

image

4) Tinting the Target Application : Using the Overlay Window button, you can view the Selected and Hotpath sub-tree elements in their target application.
If the Overlay Window button is depressed, then:

  • Selecting an element in Visual Profiler’s Element Tree will draw a yellow rectangle on that same element in the target application.
  • Hotpath elements are tinted in Red in the target application. The intensity of the Red tinting in the target application corresponds to the percentage of CPU usage.

Here is an example of how target application may look:
image

Note: Enabling this feature will slow the target application performance. In addition, tinting the target application uses Layered Windows. It is recommended that users follow this blog to make to obtain latest QFEs (or use XP Sp3 or Vista Sp1)

5) Live Preview: If the “Live Preview” is enabled, then in a live representation of the selected Element sub-tree is drawn on the bottom left. Otherwise a static image of the sub-tree is displayed.
In both cases, the image will change if another Tree Element is selected.

Note: Enabling this feature will slow the target application performance.

6) Splitter control: Allows user to adjust the various display areas (E.g. the Element Tree & Element Information areas)

7) Graph Duration Slider: Allow user to change the amount of history data collected.

8) Expander controls: Allow user to remove un-wanted clutter from the screen

9) Element Tree View: Using the View menu you can control what information is displayed on the each node in the Element Tree and remove unwanted clutter.
clip_image010

B) Much improved “Perforator” tool:
image 

The Perforator tool now provides:

1. Improved UX : More intuitive and richer UX.

2. History Data:

  • History Graphs of Frames-Per-Second, Direct Rectangles Addition Rate, HW and SW IRT count and Video Memory Usage.
  • Graph Duration slider to change the amount of history data.
  • Capture Start/Pause button to allow pause and re-capture of data.
    The History Graph value axis (Y-Axis) is now auto-adjusting.

3. Detect SW rendered Bitmap Effects: Checkbox added to tint the target application elements that use SW rendered legacy Bitmap Effects.

In below example, the top button is decorated with OuterGlowEffect Bitmap Effect. Since this effect is not HW accelerated the Button is tinted in Red.

The bottom Button is decorated with DropShadow Bitmap Effect which is HW accelerated (DropShadow is now HW accelerated in .Net 3.5 Sp1), and therefore is not tinted with Red.
image 
Known limitations:
A) You must force the target elements to redraw itself after you enabled the checkbox for you to see the red tint. E.g. hover over with the mouse, if it is standard button.
B) You still need to launch Perforator before you launch your app.

C) New tool: String Allocation Profiler
image
We added a new tool to WPFPerf called “String Allocation Profiler”
The tool enables users to view all the strings and their sizes which were allocated by the application from the time the application started till the time it closed.

To use this tool:
1. Click on “Action / Lunch Process…” to launch the target application.
Notice that WpfPerf says “Profiling…” on the status barclip_image002[4]
2. Click around your application and when done close it.
Notice that WpfPerf says “Processing Profile Data…” on the status bar
clip_image004
3. When done, WpfPerf displays the application method tree and for each method it shows the Inclusive and Exclusive # of strings allocations and their sizes.
4. You can drill down the application Method Stack Tree to view all the strings your application allocated in a specific method sub-tree.
5. Search: If you know the string names you can also search for them and find the methods that allocated them.
6. Using the “Action/Save String Allocation Log” and “Action / Save String Allocation Log” menu, you can save and open a view allocation logs at a later point.
clip_image006
Notes:
a) The tool display strings allocated directly by the application (in code and XAML) as well as strings allocated by the CLR and WPF framework.
b) The tool have affect on the performance of you application while it monitors string allocations.

D) ETW Event Tracing tool:
Some bugs fixed, and new detailed documentation for the WPF ETW events is now available. See more here.

E) General improvements:
1) Numerous bug fixes
2) Now you can attach and profile XBAPs in addition to Standalone WPF apps
3) Improved “Add Tool” dialog. 
    It now allows user to select more than one tool at a time.
clip_image002[6]
4) UI improvements to the “Select Process” dialog.
    This allows user to select the target application to profile.
clip_image004[5]
5) UI improvements to the “Launch Process” dialog.
clip_image006[5]

F) Know issues and Caveats:

  1. General:
    Try to avoid using more than one tool (e.g. Visual profiler & Perforator) at the same time to profile the same app as it will decrease the application performance.
  2. Perforator/ Detect SW rendered Bitmap Effects:
    When you set “Detect SW rendered Bitmap Effects”, in order for the Red tint to show, you must force the target elements to redraw itself.
  3. Perforator/ Overlay Window:
    Tinting the target application uses Layered Windows. It is recommended that users follow this blog to make to obtain latest QFEs (or use XP Sp3 or Vista Sp1)
  4. Perforator/ Live Preview:
    Live Preview uses Visual brush, so if you also use Perforator to profile the same app, you may see that the HW IRT count increases by 1.
  5. Perforator/Visual profiler
    You can attach to an XBAP (by attaching to PresentationHost.exe), but you may not able to launch an XBAP.
  6. Perforator/Visual profiler
    You must launch Perforator before you launch your app.

Please enjoy the tool and tell us what you think and what needs improvement.

Posted by jgoldb | 15 Comments

Improving Microsoft DataGrid CTP sorting performance - Part 2

In this blog I wrote how you can improve Microsoft DataGrid CTP by providing your own custom sort.  
As one of the comments suggested you can get even better performance by using delegates.
I have changed MySort code below and I now use delegates to avoid the switch comparison that was called on every compare during the QuickSort . I can now see additional ~50% speed gain during sort.

In my 300,000 rows DataGrid, before I saw sort speed decreased from almost 5 minutes to 2.4 seconds and now the String type columns (e.g. Name, Position) are sorted in 1.4 sec while the Integer type columns (e.g. Id) are now sorted in 400 ms!

   1:  public class MySort : IComparer
   2:  {
   3:        public delegate int TwoArgDelegate(Employee arg1, Employee arg2);
   4:        TwoArgDelegate myCompare;
   5:        public MySort(ListSortDirection direction, DataGridColumn column)
   6:        {
   7:                  int dir = (direction == ListSortDirection.Ascending) ? 1 : -1;
   8:                  //set a delegate to be called by IComparer.Compare
   9:                  switch ((string)column.Header)
  10:                  {
  11:                      case "Id":
  12:                          myCompare = (a, b) => { return a.Id.CompareTo(b.Id) * dir; };
  13:                          break;
  14:                      case "Name":
  15:                          myCompare = (a, b) => { return a.Name.CompareTo(b.Name) * dir; };
  16:                          break;
  17:                      case "Position":
  18:                          myCompare = (a, b) => { return a.Position.CompareTo(b.Position) * dir; };
  19:                          break;
  20:                      case "Tel":
  21:                          myCompare = (a, b) => { return a.Telephone.CompareTo(b.Telephone) * dir; };
  22:                          break;
  23:                      case "Email":
  24:                          myCompare = (a, b) => { return a.Email.CompareTo(b.Email) * dir; };
  25:                          break;
  26:                      case "Enabled":
  27:                          myCompare = (a, b) => { return a.Enabled.CompareTo(b.Enabled) * dir; };
  28:                          break;
  29:                      case "City":
  30:                          myCompare = (a, b) => { return a.City.CompareTo(b.City) * dir; };
  31:                          break;
  32:                      case "Country":
  33:                          myCompare = (a, b) => { return a.Country.CompareTo(b.Country) * dir; };
  34:                          break;
  35:                      default:
  36:                          myCompare = (a, b) => { return 0; };
  37:                          break;
  38:                  }
  39:              }
  40:              int IComparer.Compare(object X, object Y)
  41:              {
  42:                  return myCompare((Employee)X, (Employee)Y);
  43:              }
  44:      }
  45:  }
Posted by jgoldb | 4 Comments

Attachment(s): DataGridSort2.zip

Improving Microsoft DataGrid CTP sorting performance

Summary:

As you may know Microsoft released a Community Tech Preview (CTP) of the DataGrid control. See the posting here.
Once you start using the DataGrid CTP, load many elements to it and you use the default, built-in sort (by simply clicking on the DataGrid column headers) you may notice that sorting can be very slow.
The reason is that the comparer that is built-in to the MS DataGrid knows nothing about your data type and currently use reflection which is very costly.

In this blog I wanted to point you to a simple approach that could significantly improve the sorting performance of your DataGrid.

Approach:

If you load many elements to the MS DataGrid and use the built-in sort which currently use reflection, you may find sorting to be very slow.

Fortunately, for many scenarios you can implement your IComparer and provide it in the CustomSort property. You could achieve significant performance gains by doing so, in my example I was able to achieve 100x speed improvement.

In my 300,000 rows DataGrid, sort speed decreased from almost 5 minutes to 2.4 seconds !
(The provided download only loads 6,000 rows, but you are welcome to change...)

image

Code:
public partial class Window1 : System.Windows.Window
{
    private bool UseCustomSort
    {
        get { return CustomSortCB.IsChecked == true; }
    }
 
    private void WPF_DataGrid_Sorting(object sender, DataGridSortingEventArgs e)
    {
        if (_stopwatch == null)
        {
            _stopwatch = new Stopwatch();
        }
        else
        {
            _stopwatch.Reset();
        }
 
        _stopwatch.Start();
        if (UseCustomSort)
        {
            e.Handled = true;   // prevent the built-in sort from sorting
            PerformCustomSort(e.Column);
            CustomSortingDone();
        }
        else
        {
            Dispatcher.BeginInvoke(DispatcherPriority.Normal, new NoArgDelegate(StandardSortingDone));
        }
    }
 
    private void StandardSortingDone()
    {
        _stopwatch.Stop();
        statusTextBlock1.Text = "Buit-in Sort: " + _stopwatch.ElapsedMilliseconds.ToString() + " msec";
    }
    private void CustomSortingDone()
    {
        _stopwatch.Stop();
        statusTextBlock2.Text = "Custom Sort: " + _stopwatch.ElapsedMilliseconds.ToString() + " msec";
    }
    private void PerformCustomSort(DataGridColumn column)
    {
 
        ListSortDirection direction = (column.SortDirection != ListSortDirection.Ascending) ? 
                                 ListSortDirection.Ascending : ListSortDirection.Descending;
        column.SortDirection = direction;
        ListCollectionView lcv = (ListCollectionView)CollectionViewSource.GetDefaultView(WPF_DataGrid.ItemsSource);
        MySort mySort = new MySort(direction, column);
        lcv.CustomSort = mySort;  // provide our own sort
    }
 
    public class MySort : IComparer
    {
        public MySort(ListSortDirection direction, DataGridColumn column)
        {
            Direction = direction;
            Column = column;
        }
 
        public ListSortDirection Direction
        {
            get;
            private set;
        }
 
        public DataGridColumn Column
        {
            get;
            private set;
        }
 
        int StringCompare(string s1, string s2)
        {
            if (Direction == ListSortDirection.Ascending)
                return s1.CompareTo(s2);
            return s2.CompareTo(s1);
        }
 
        int IComparer.Compare(object X, object Y)
        {
            int int1, int2;
            string str1, str2;
            switch ((string)Column.Header)
            {
                case "Id":
                    int1 = ((Employee)(X)).Id;
                    int2 = ((Employee)(Y)).Id;
                    if (Direction == ListSortDirection.Ascending)
                        return int1.CompareTo(int2);
                    return int2.CompareTo(int1);
                case "Name":
                    str1 = ((Employee)X).Name;
                    str2 = ((Employee)Y).Name;
                    return StringCompare(str1, str2);
                // ... do same for other columns
     
              }
            return 0;
        }
    }
   private Stopwatch _stopwatch;
}

XAML Code:
<Window x:Class="DataGridSortDemo.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:sys="clr-namespace:System;assembly=mscorlib"
    xmlns:local="clr-namespace:DataGridSortDemo"
    xmlns:dg="http://schemas.microsoft.com/wpf/2008/toolkit"
    xmlns:xcdg="http://schemas.xceed.com/wpf/xaml/datagrid"
    Title="Microsoft DataGrid Sort Example" Height="760" Width="850"
    >
    <Window.Resources>
        <local:Employees x:Key="employees" />
    </Window.Resources>
  <Grid>
    <Grid.RowDefinitions>
      <RowDefinition MinHeight="25" Height="Auto"/>
      <RowDefinition MinHeight="3in" Height="*" />
      <RowDefinition Height="Auto" MinHeight="10" />
      <RowDefinition Height="Auto" MinHeight="10" />
      <RowDefinition Height="Auto" MinHeight="10" />
      <RowDefinition Height="Auto" MinHeight="10" />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="Auto" />
    </Grid.ColumnDefinitions>
 
 
    <dg:DataGrid x:Name="WPF_DataGrid" FontSize="12pt"
                 Grid.Row="1" Grid.Column="0"  Margin="10,2,10,2"
                 AutoGenerateColumns="False"
                 Sorting="WPF_DataGrid_Sorting"
                 ItemsSource="{StaticResource employees}"
              >
            
      <dg:DataGrid.Columns>
        <dg:DataGridTextColumn Width="Auto" Header="Id" DataFieldBinding="{Binding Path=Id}"></dg:DataGridTextColumn>
        <dg:DataGridTextColumn Width="Auto" Header="Name" DataFieldBinding="{Binding Path=Name}"></dg:DataGridTextColumn>
        <dg:DataGridTextColumn Width="Auto" Header="Position" DataFieldBinding="{Binding Path=Position}"></dg:DataGridTextColumn>
        <dg:DataGridTextColumn Width="Auto" Header="Tel" DataFieldBinding="{Binding Path=Telephone}"></dg:DataGridTextColumn>
        <dg:DataGridTextColumn Width="Auto" Header="Email" DataFieldBinding="{Binding Path=Email}"></dg:DataGridTextColumn>
        <dg:DataGridTextColumn Width="Auto" Header="Enabled" DataFieldBinding="{Binding Path=Enabled}"></dg:DataGridTextColumn>
        <dg:DataGridTextColumn Width="Auto" Header="City" DataFieldBinding="{Binding Path=City}"></dg:DataGridTextColumn>
        <dg:DataGridTextColumn Width="Auto" Header="Country" DataFieldBinding="{Binding Path=Country}"></dg:DataGridTextColumn>
     </dg:DataGrid.Columns>
    </dg:DataGrid>
 
    <TextBlock Grid.Row="2" Name="statusTextBlock1" Foreground="Red"
               FontSize="12pt" Text="" />
    <TextBlock Grid.Row="3" Grid.Column="0" Name="statusTextBlock2" Foreground="Green"
               FontSize="12pt"  Text=""  />
    <CheckBox  Name="CustomSortCB" FontWeight="Bold"  FontSize="12pt" Grid.Row="0" Grid.Column="0" Margin="10,6,6,6"
               Foreground="Blue">
      Use Custom Sort  [Check / Uncheck box, then Click on the DataGrid header to compare Sort performance]
    </CheckBox>
 
 
  </Grid>
</Window>
Caveats:

You can only use the CustomSort if your DataGrid is bound to an IList. You cannot use the CustomSort if you bound to an instance of IBindingList such as DataView. In this case the class that derives from ICollectionView is a BindingListCollectionView which does not have a custom sort property. The view in this case delegates the Sort logic to the underlying DataView which does not allow sort customization.

Posted by jgoldb | 9 Comments

Attachment(s): DataGridSort.zip

What’s new in WPF 3.5 SP1: Splash Screen to improve perceived startup perf

Summary:

To improve the perception of a more responsive startup experience many WPF applications added a Splash Screen to their startup.  The Splash Screen, which does not load WPF code shows as soon as possible and is displayed until the application main window is rendered.
Up until 3.5 Sp1 we pointed developers to sample code available on this blog.
In  the just released .Net 3.5 SP1 we added basic Splash Screen support and new APIs and we recommend that you take advantage of it. (See download locations below)

A Visual Studio 2008 Sp1 Item Template that makes adding a Splash Screen much easier is available on WPF Futures site on www.codeplex.com/wpf.

How to Use:

     Approach A:

The easiest way to add is by using VS 2008  SP1.
·  Create a new Standalone VB or C# WPF project in VS 2008 Sp1.  Verify “Target Framework” project property is “.Net Framework 3.5”

·   Add an image (your splash screen image) to the project (e.g. by drag and drop) 

·   Set the image BuildAction to SplashScreen

·   Do F5 ( Build+Run), splash screen should be shown.

·   To disable the Splash Screen image functionality you can either:

   o    Remove the “SplashScreen.png” image from the project, or

   o Set the splash image BuildAction to ‘None’.

image

Upon compile, the build (PresentationBuildTasks.dll) will generates below code in App.g.cs:

   1: SplashScreen splashScreen = new SplashScreen("Splashscreen1.png");
   2: splashScreen.Show(true);
   3: MyApp.App app = new MyApp.App();
   4: app.InitializeComponent();
   5: app.Run();

Note:  Above code will be generated in VS 2008 Sp1 only if the “Target Framework” project property is “.Net Framework 3.5”. Otherwise no code will be generated.

Approach B:

Install the Splash Screen Visual Studio 2008 Sp1 Item Template from the WPF Futures site.

·   Create a new Standalone VB or C# WPF project in VS 2008 Sp1.  Verify “Target Framework” project property is “.Net Framework 3.5”

·   In VS,  Right-Click on your Project and then select “Add / New Item… / Splash Screen (WPF)”.

·   Notice the new image BuildAction  is set to SplashScreen for you.

·   Do F5 (Build+Run), the default splash screen image that was installed with the template will be shown (you likely want to replace with your own Splash Screen image)

image

Approach C:

Another approach is to directly use the new public Splash Screen APIs. With this approach you can set the ‘BuildAction=Resource’.
For example you can call the following code:

   1: SplashScreen appSplash = new SplashScreen("Splashscreen1.png");
   2: appSplash.Show(false);
   3: //….do some work…
   4: appSplash.Close( TimeSpan.FromSeconds(0.3)); // Splash to fadeout in 300ms

The WPF Splash Screen APIs are defined as below:

   1: namespace System.Windows
   2: {
   3:     public class SplashScreen
   4:     {
   5:         public SplashScreen(string resourceName);
   6:         public SplashScreen(Assembly resourceAssembly, string resourceName);
   7:         public void Show(bool autoClose);
   8:         public void Close(TimeSpan fadeOutDuration);    
   9:     }
  10: }

public ApplicationSplashScreen(string resourceName)

Behavior

Constructor.  resourceName points to the embedded splash image

Exceptions

 none

public ApplicationSplashScreen(Assembly resourceAssembly, string resourceName)

Behavior

Constructor. resourceAssembly specify the assembly in which resources lives resourceName points to the embedded splash image

Exceptions

 none

public void Show(bool autoClose);

Behavior

Constructor. Shows the splash image.

If autoClose is true, the code uses the dispatcher to queue an item at Idle priority, enabling the Splash screen to start fading out using the default fadeOutDuration (300 msec) after the application first renders. 

If autoClose is false, the app is responsible to call Close(fadeOutDuration), in this case the splash screen fades out using the provided fadeOutDuration.

Exceptions

 IOException if resource provided in constructor not found in app assembly

public void Close(TimeSpan fadeOutDuration)

Behavior

Closes the splash window. 

fadeOutDuration is the time for splash screen to fade out. If autoClose is true, WPF will close the window and use a 300 msec as the default fadeOutDuration.

Exceptions

none

Caveats:

It is important to understand that the Splash Screen has the following limitations:
·         It does not actually improve application cold startup time.
·         Cannot display sequence of splash images or animation.
·         Does not support for animated GIFs
·         Does not support earlier versions of VS (earlier than VS2008 Sp1). You should still be able to use the APIs (e.g. Approach C)

·         Does not support XBAPs (XBAPs already have their own improved coldstart progress page in  .Net 3.5 Sp1)
·         Does not have  XAML support for setting splash screen image
·         Expression Blend does not provide UI to  set the SplashScreen build action

.Net 3.5 SP1 Download locations:

Content

Links

Visual Studio 2008 Express Editions with Service Pack 1 (Bootstrappers)

http://go.microsoft.com/fwlink/?LinkId=123679

Visual Studio 2008 Express Editions with Service Pack 1 (iso)

http://go.microsoft.com/fwlink/?LinkId=123680

Visual Studio 2008 Service Pack 1 (Bootstrapper)

http://go.microsoft.com/fwlink/?LinkId=122094

Visual Studio 2008 Service Pack 1 (iso)

http://go.microsoft.com/fwlink/?LinkId=122095

Visual Studio  Team System 2008 Team Foundation Server Service Pack 1

http://go.microsoft.com/fwlink/?LinkId=124829

.NET Framework 3.5 Service Pack 1

http://go.microsoft.com/fwlink/?LinkId=124150

 

Posted by jgoldb | 12 Comments

Improve WPF application startup using ClickOnce On-Demand Download

In this blog (see item 11.) we discussed the fact that ClickOnce can have a significant effect on application start app time.

For standalone applications (both WPF and Winform apps) if you use the default settings in Visual Studio, ClickOnce will access the site-of-origin server (e.g. company network or internet) to check for a newer version before the application start. As expected, this will slow down the overall application startup. You can consider modifying this default setting to check for a new version after the application starts.

In the XBAP case this is not configurable. ClickOnce will always check the deployment site (site-of-origin) for updates before the XBAP starts.

In certain scenarios, you can consider using the ClickOnce Deployment APIs to download a smaller part of your application (for example, code required only for the first screen of the application) and download the rest of your app modules at a later stage, in the background, as they are needed. If your app is large, this could significantly improve your application startup performance the first time it runs.

It is also very possible that your end-user will not use certain portions of the application, so if you can identify what they are and avoid downloading them it could provide a big win.

Below I have a sample XBAP that shows how you can use the ClickOnce Deployment APIs to achieve this. Note that this approach works both for Standalone and XBAPs applications.

Although the overall size of my sample is 13MB in size, the application downloads and displays relatively quickly since at first we only download the main app module which is only 9KB in size.

The large image resources (~13MB) are contained in a separate module (SimpleOnDemandLibraray.dll) and are not downloaded at startup. SimpleOnDemandLibraray.dll is downloaded in the background from the XBAP site-of-origin only when user clicks on the button.

After launching XBAP this is what is shown:

OnDemand1 

Only when users click on the button the ~13MB module (SimpleOnDemandLibraray.dll) which contains the image resources downloads in the background.
Your app could display a fancier progress UX then mine…:)
OnDemand2
Sometime later, when download completes the image shows as below:OnDemand3

To enable this you need specifcy that SimpleOnDemandLibraray.dll is an optional component.
You can do this in Visual Studio in the Properties/Publish/ Application Files property page like here:

OnDemand4

The code is very simple and looks like this:

private void InvokeDownloadGroup(object sender, RoutedEventArgs e)
{
     try
     {
        Status.Visibility = Visibility.Visible;      
        ApplicationDeployment thisApp = ApplicationDeployment.CurrentDeployment;
        thisApp.DownloadFileGroupCompleted +=
                  new DownloadFileGroupCompletedEventHandler(DownloadFileGroupCompleted);
        thisApp.DownloadFileGroupAsync("OnDemandGroup1"); // Start the download
      }
      catch (Exception exp)
      {
        Status.Visibility = Visibility.Collapsed;
        onDemandResult.Content = "Failed: " + exp.Message.ToString();
      }
}
 
// Called when download completes
void DownloadFileGroupCompleted(object sender, DownloadFileGroupCompletedEventArgs e)
{
     Status.Visibility = Visibility.Collapsed;
     // Show an image from the downloaded group to demonstrate it is available from this 
     // event forward...
     Image myImage = new Image();
     BitmapImage myBitmapImage = new BitmapImage();
     myBitmapImage.BeginInit();
     myBitmapImage.UriSource = 
                new Uri("pack://application:,,,/SimpleOnDemandLibrary;component/LargeImage.JPG");
     myBitmapImage.EndInit();
     myImage.Source = myBitmapImage;
     MyParent.Children.Add(myImage);
}

Special thanks to Matt Galbraith who helped with this sample.

More info on the ClickOnce Deployment API is here: http://msdn.microsoft.com/en-us/library/ak58kz04(VS.80).aspx

To download XBAP sample (.zip) click here.

Posted by jgoldb | 1 Comments

What’s New for Performance in WPF in .Net 3.5 SP1

As you know the .NET Framework 3.5 Service Pack 1 Beta download is now available. There are many improvements in this release that we are very excited about. Scott Guthrie blogged about these improvements here and so did Tim Sneath. In this blog I want to specifically focus and provide more details on the performance improvements coming in WPF.

Graphics Improvements

Significantly improved BitmapEffects performance

  • Up until .Net 3.5 SP1, all BitmapEffects were rendered in Software, now the Blur and DropShadow BitmapEffects are Hardware Accelerated and rendered by the GPU.
    We measured ~5x CPU, frame rate and video memory usage gains in by using the GPU for some scenarios.
  • It is important to note that the other built-in effects, (namely OuterGlow, Bevel, Emboss) continue to render in Software and should be avoided.
  • “Most’’ apps see gains simply by upgrading to .Net 3.5 SP1, without re-compile.
  • No gains will be seen after upgrade if the app uses effects that are:
    • Are used in an EffectGroup
    • Have too large a blur radius
    • Aren’t running on a Tier-2 video card (DX Ver. >= 9.0)
  • New Effects (now called BlurEffect, DropShadowEffect ) are introduced and these will always be Hardware Accelerated.
  • It is recommended that you do not use old Effects: BevelBitmapEffect, BlurBitmapEffect, DropShadowBitmapEffect, BevelBitmapEffect, EmbossBitmapEffect, OuterGlowBitmapEffect as these are being marked obsolete. Instead use the new effects.
  • Note that the legacy Effects extensibility mechanism has not been accelerated

New Effect Extensibility

  • We added support to Hardware Accelerated HLSL shaders with the new ShaderEffect class
  • These extensible effects can expose dependency properties that can be written/read to/from, animated and data- bound just like any other DPs
  • Currently we support full-trust only
  • Support "multi-input" effects where multiple UIElements can be provided to and manipulated by an Effect.  (included only in final RTM bits)
  • See more details in Greg Schechter’s blog.

Improved DirectX Integration

  • New D3DImage class, enabled developer to overlay or blend Direct3D content interchangeably with WPF content (e.g. use the Direct3D surface as a brush for WPF content, or apply it as a texture within a WPF 3D scene ) without any major performance impact.
  • Note: this feature will only be available in the RTM bits

Improvements to WriteableBitmap

  • WriteableBitmap is a mechanism for drawing & updating a system-memory bitmap to the screen on a per-frame basis.
  • This feature was available before, but before we allocated a new bitmap with every frame update, which made it too slow for some scenarios.
  • The new implementation is now much more efficient; it is synchronized with UI changes and has constant memory usage. This enables new scenarios such as, paint programs, fractal renderers, scatter plots, music visualization and other complex geometries that were not possible before.
  • Note: it is recommended that you use BGR32 or pBGRA32 pixel formats when possible. Other formats must run through a format converter each frame, which reduces perf.

Improved Text Performance

  • We improved our glyph management infrastructure which provides noticeable faster text rendering speed. Note that these gains will be mostly noticeable in specific scenarios such as VisualBrushes, DrawingBrushes, Viewport2DVisual3D , and not everywhere

Improved Z-index Scenarios

  • We significantly improved performance of scenarios that continuously modify Z-Index property of Panel elements (such as in a 2D Carrousel scenario)

Remoting

Although we have not improved this scenario, it is important to highlight some differences related to Remoting
On .Net Framework 3.0 and .Net Framework 3.5:

  • Vista to Vista with DWM on, we Remoted content as Primitives (e.g. the channel protocol went over the network) (This is for the Remote Desktop case only, not Terminal Server)
  • In other cases: we Remoted content as Bitmaps

On .Net Framework 3.5 SP1

  • We now remote as bitmaps in ALL cases.
  • The reason is that WPF 3.5 SP1 now uses a new graphics DLL (wpfgfx.dll) and certain changes could not be made to Vista’s existing graphics DLL (milcore.dll) that is also used by DWM.
  • Although this could be seen a regression at first, depending on the complexity of the application scene (e.g. very rich scenes) this can actually improve performance in certain scenarios . Also, connections with reasonably high bandwidth and scenarios that don’t involve a lot of animation or 3D, for instance, tend to remote just fine via bitmaps.

New “Nearest Neighbor” BitmapScaling Mode

  • We added NearestNeighbor interpolation mode to the BitmapScalingMode enumeration. This should provide further performance benefits over LowQuality mode when using the software rasterizer and more importantly, it provides missing functionality to scenarios such zoom-in while editing a bitmap in a “Paint” program. Without this feature WPF would produce blurry results.

Minor improvement to Tier APIs

  • Two new members added to RenderCapability class to allow applications to fine-tune their use of shader-based Effects:
    • IsPixelShaderVersionSupported(major, minor) : indicates whether the system the specified Pixel Shader version on the GPU.  This is useful for understanding whether effects that you want to run will run in H, as you may potentially want to exclude them if they don't run in hardware.
    • IsShaderEffectSoftwareRenderingSupported: Boolean indicating whether the system supports SSE2 and where the HLSL “JIT” will work.

Smoother animations

  • Almost all of our Animation smoothing improvements already included in .Net 3.5 , however some additional (smaller) improvements are included in Vista Service Pack 1.

Layered Windows improvements

I have blogged about the availability of QFEs for Vista and XP before.
These fixes now included in the recently released Windows XP Service Pack 3 and in Vista Service Pack 1
Note that there is a difference fix on each platform.
On XP: Huge improvements as now render in HW vs. SW before
On Vista: Smaller but still significant improvement to readback from GPU

Controls Improvements

Improved scrolling performance (by introducing Container Recycling support)

  • As user is scrolling through items in a control we re-use the UI elements that go out of view (as oppose to destroy and recreate these elements in .Net 3.0 and 3.5). This turns out to provide significant scrolling improvements.
    We see up to 40% scroll performance improvement in the basic case (e.g. elements contain text). We call this feature Container Recycling.
  • Container Recycling is supported in WPF controls that use VirtualizingStackPanel, namely: ListView, ListBox, TreeView
  • This is an opt in feature, your app need to add the Recycling mode to take advantage of this improvement:
    <ListBox …VirtualizingStackPanel.VirtualizationMode="Recycling" />

Added virtualization support to TreeView control

  • We now added virtualization support to the TreeView control, similar to ListView and ListBox.
  • This ensures that TreeView is not consuming huge amount of memory when it contains large number of elements (e.g. 1,000’s) and it also expends much faster. This enable scenarios that were not possible before (e.g. Windows Explorer) .
  • This is an opt in feature, your app need to use IsVirtualizing in order to take advantage of this improvement:
    <TreeView …VirtualizingStackPanel.IsVirtualizing = “true” />
  • Note that the TreeView also supports the Container Recycling feature mentioned above, so in order to take advantage of this improvement you must do:
    <TreeView …VirtualizingStackPanel.IsVirtualizing=“true”...  VirtualizingStackPanel.VirtualizationMode="Recycling" />

Deferred Scrolling

  • This provides a perceived perf improvement for scrolling. It keeps the content in view as static until scrolling is complete, similar to how Microsoft Outlook scrolls.
  • You could use the ScrollViewer.ScrollChanged event and write your own code to display preview thumbnail during scroll if you like.
  • This is an opt in feature, so your app needs to add IsDeferredScrollingEnabled property in order to take advantage of this feature. E.g.
    <ListBox …ScrollViewer.IsDeferredScrollingEnabled = “true" />

Better fundamentals for DataGrid control
Various enhancements were made to enable developers to write a faster and better DataGrid:

  • Container Recycling
    • Discussed earlier…
  • Column Virtualization Extensions
    • New APIs added to VirtualizingStackPanel that exposes hooks to enable writing your own custom panel with virtualization in the horizontal direction. These could be used by a DataGrid or by other custom panels.
  • Other non-perf DataGrid related features:
    • MultiSelector support to handle multi-selection and bulk editing scenarios
    • IEditableCollectionView - New interface between data controls and data source that enables editing/adding/removing items in a transactional way.
    • StringFormat - shortcut to display data bound number as formatted text
    • Alternating Rows - Enables setting alternating properties on rows of ItemsControl (e.g. alternating background colors in a DataGrid)
    • Conversions for Null Values - Recognize null values in editable controls and convert to appropriate value based on type. It also adds TargetNullValue property which enables app author to designate any value as equivalent to “null”
    • Item-Level Validation - By using Binding Groups this applies validation rules to an entire bound item. For example it can enable validate & commit scenario for a form with few bind-able edit fields. (available in final RTM bits only)
Startup Improvements

Various enhancements were made to improve WPF application startup time
a) Improved Coldstart time

  • By optimizing how we layout the code blocks within CLR and WPF NGEN images we improved the disk IO access patterns we are measuring up to 40% faster coldstart time on average. (we define 'coldstart' for the first WPF app you launch after system re-boot)
  • These gains are depending on the scenario and the application size. Larger apps likely to see better gains than small apps.

b) Improved coldstart for strong-name signed assemblies not GAC’d.
In certain deployment scenarios, an app author may choose to strong-name sign their application assemblies but not to GAC the assemblies because it requires admin privileges.
In this scenario, the entire assembly had to be read off the disk so the CLR can do the hash verification. This had a significant coldstart hit.
In .Net 3.5 SP1 the CLR bypassed this hash verification by default, which means that the app have less disk seeks and disk read and therefore startup time is improved. (As indicated in this blog the majority of coldstart time is spent on disk access.)
The expected startup gains depends on the assemblies size and on what else the app is doing in its startup, but in one scenario we measured ~5% coldstart gains in addition to the gains measured in (a).
If you want to disable this default, an app author can provide a config file (e.g. YourApp.exe.config) and add this:
<configuration>
      <runtime>
             <bypassTrustedAppStrongNames enabled=”0” /> 
    </runtime>
</configuration>
You can find more details in this blog.

c) XBAP coldstart improvements

  • By improving the concurrency of the ClickOnce download sequence we are now seeing up to 10% startup gains for XBAPs scenarios in addition to the gains measured in (a).
  • Up until 3.5 SP1, the XBAP progress UX was rendered using WPF, which means we had to coldstart the CLR and WPF. Starting with .Net 3.5 SP1, we now render the progress UX using HTML which will be shown almost instantly and will improve the perceived startup performance.

d) Splash Screen to improve perceived startup

  • Although coldstart time is improved, it is still not instant. In .Net 3.5 SP1 we are adding new public Splash Screen APIs to allow developers to easily add Splash Screen and make their application startup experience more responsive.
  • Some simple customization is possible with these APIs.
  • An intuitive integration with Visual Studio 2008 SP1 to make this experience even easier is coming in RTM.
  • Note: these APIs will only be available in the RTM bits

Important note: Although we made some impressive improvements to WPF application startup, don’t expect it to be as fast as Win32 application or Winform. WPF simply load more code off the disk. We still expect application developers to properly optimize their app for faster startup and follow the recommendations provided in this blog.

Deployment Improvements
  • .NET Framework 3.5 Client Profile (Client Profile): Smaller and faster redistribution of .Net Framework 3.5 SP1 with a download size of close to 28MB for client applications.
  • Brand-able deployment UX
  • New, smaller deployment and bootstrapper
  • Framework install integrated with Application. Installer can launch app after the framework installed. Supports .msi, .application or .xbap
  • Read more in this blog as well as this

Other Improvements

Memory footprint

  • Modest improvements to working set, especially during startup
  • We fixed few memory leaks mostly related to usage of Image control.
    More details and additional info on how to find and avoid memory leaks in WPF is in my blog.

Improvements to NGEN / JIT

  • The NGEN throughput is improved
  • Modest improvements to JIT time & execution time of the JIT-ed code

Memory Leaks in WPF based applications – Blog Update

We discovered few other potential memory leaks that WPF based application can encounter so I wanted to update my original Finding Memory Leaks in WPF-based applications blog and the sample in that blog with more info on these potential leaks.

Please review the blog updates and use the suggested workarounds to avoid such leaks in your WPF application (or upgrade to the .Net 3.5 Sp1 release when it becomes available).

These potential memory leaks could happen if you use the Image control when:

a) You use BitmapImage as the Image source and do not release the BitmapImage. E.g:

static BitmapImage bi1 = new BitmapImage(new Uri("Bitmap1.bmp",UriKind.RelativeOrAbsolute));
m_Image1 = new Image();
m_Image1.Source = bi1; 
//bi1.Freeze() //if you do not Freeze, your app will leak memory MyStackPanel.Children.Add(m_Image1);

b) You assign multiple BitmapImage as the Image source and do not release all of the BitmapImage you used (similar to (a)). This one introduced in .Net 3.5 ). E.g.:

static BitmapImage bi1 = new BitmapImage(new Uri("Bitmap1.bmp",
UriKind.RelativeOrAbsolute));
static BitmapImage bi2 = new BitmapImage(new Uri("Bitmap2.bmp",
UriKind.RelativeOrAbsolute));
bi2.Freeze();
m_Image1 = new Image();
//bi1.Freeze() //even though you are really using bi2 for Image Source, you also need to Freeze bi1 it to avoid leak m_Image1.Source = bi1; // use un-frozen bitmap, which causes the leak m_Image1.Source = bi2; // use frozen bitmap MyStackPanel.Children.Add(m_Image1);

c) You use BitmapImage that was downloaded from the Web as the Image source. E.g. below will leak:

BitmapImage image = new BitmapImage();
image.BeginInit();
image.UriSource = new Uri(@"http://www.somesite.com/some_image.png", UriKind.RelativeOrAbsolute);
image.CacheOption = BitmapCacheOption.OnLoad;
image.CreateOptions = BitmapCreateOptions.None;
image.EndInit();                
m_Image1 = new Image();
m_Image1.Source = image;   
MyStackPanel.Children.Add(m_Image1);

See items (5), (6) and (7) in the blog for more detailed documentation, samples and workarounds.

Please note that these are fixed in the upcoming .Net 3.5 Sp1 release, so one potential workaround is to upgrade.

Posted by jgoldb | 1 Comments

WPF Performance Suite Download Location

Few people asked me for the public download location of our WPF Performance Suite.
On 9/25/2008, we updated this tool. See this blog: http://blogs.msdn.com/jgoldb/archive/2008/09/25/updated-wpfperf-performance-profiling-tools-for-wpf.aspx

Posted by jgoldb | 1 Comments

Quick tips to improve WPF app memory footprint.

We sometimes hear concerns that WPF applications memory foot print is too large.

This could be because of many reasons, but a common reason is that the application simply contains large number of elements in its visual tree. Very large tree will increase memory consumption and cause severe sluggishness.

Very often the root cause is that Virtualization got turned off. As you know Virtualization is on by default in WPF ListBox & ListView controls, but certain conditions can turn it off (see conditions below) even if you did not intent to!

Another possible cause is that the application uses rich templates that can quickly causes elements count to grow.

A good tool that can help you isolate these kinds of issues is Snoop.

In the image below, you can see that the app is using the Virtualizes Stack panel, however you can see that the ListBox contains thousand of elements, not as expected.

Snoop 

Snoop allows you to quickly filter properties, so if you type "IsGr" in the Property Filter box,  you can see that the IsGrouping property is checked. In this example , the the application turned Grouping on, which causes Virtualization to be turned off.

image

In summary:

  • Use Snoop to watch if your application has too many elements.
  • Check if number of elements grew because of your templates and optimize those if possible.
  • Watch for below conditions that may turn virtualization off in ListBox/ListView:
    1. Make sure ScrollViewer.CanContentScroll=True
    2. Make sure VirtualizingStackPanel.IsVirtualizing=True
    3. Avoid Grouping
    4. Keep VirtualizingStackPanel as your default panel …or write own virtualized panel. A good example is the Virtual Canvas described here.
Posted by jgoldb | 5 Comments

Virtualized WPF Canvas

As you may already know WPF has a built-in virtualizing panel called VirtualizingStackPanel that supports UI virtualization and lays out its elements like StackPanel.

The WPF ListBox & ListView controls use this panel by default. Other containers controls such as Canvas do not have virtualization support in .Net 3.0 & 3.5.

Chris Lovett from Microsoft now wrote a great sample that shows how you can also virtualize a Canvas container control so it can efficiently host and scroll thousands of WPF elements without consuming huge amount of memory.  

The provided down-loadable ZIP has a white paper and the code.

Hope you find this useful.

Jossef.

Posted by jgoldb | 6 Comments
Attachment(s): VirtualCanvas.zip
More Posts Next page »
 
Page view tracker