WinUI 3 Performance Boost

WPF Team Blog
24 January 2022

Performance and UI rendering speed remains at the top of our WinUI priority list. In this blog post, we will describe performance challenges we’ve encountered with WinUI and what we’ve done to address these issues. We’ll also show you how we created the fastest Data Grid for Microsoft’s new WinUI platform.

WinUI Performance Bottlenecks

First a refresher as to how the WinUI platform was constructed and architectural differences from its predecessors (WPF and WinForms). In WPF and WinForms, components and their core logic are implemented within standard .NET libraries. For example, base WPF classes such as DependencyObject are fully implemented in .NET and you can always see what logic is executed when a dependency property changes. Unmanaged code is used only for UI rendering and user interaction (implemented using Windows API calls).

In WinUI, all internal logic is implemented with native WinRT components and Windows App SDK ships only .NET wrappers for these components. The DependencyObject class initializes a WinRT object mapped to the IDependencyObject interface and uses this object when a dependency property setter or getter is invoked:

[WindowsRuntimeType("Microsoft.UI")]
[Guid("9FB92D6F-2CC3-5892-ABB3-45F6461EA7E4")]
[ContractVersion(typeof(WinUIContract), 65536)]
internal interface IDependencyObject
{
    object GetValue(DependencyProperty dp);
    void SetValue(DependencyProperty dp, object value);
    //...
}
public class DependencyObject : ICustomQueryInterface, IWinRTObject, IDynamicInterfaceCastable, IEquatable<DependencyObject>
{
    public object GetValue(DependencyProperty dp) => this._default.GetValue(dp);
    public void SetValue(DependencyProperty dp, object value) => this._default.SetValue(dp, value);

    private IObjectReference _inner;
    private IDependencyObject _default => this._defaultLazy.Value;
    private readonly Lazy<IDependencyObject> _defaultLazy;

    protected DependencyObject()
    {
        bool flag = this.GetType() != typeof(DependencyObject);
        IntPtr innerInterface;
        IntPtr instance = DependencyObject._IDependencyObjectFactory.Instance.CreateInstance(flag ? (object)this : (object)(DependencyObject)null, out innerInterface);
        try
        {
            ComWrappersHelper.Init(flag, (object)this, instance, innerInterface, ref this._inner);
            this._defaultLazy = new Lazy<IDependencyObject>((Func<IDependencyObject>)(() => (IDependencyObject)new SingleInterfaceOptimizedObject(typeof(IDependencyObject), this._inner)));
            this._lazyInterfaces = new Dictionary<Type, object>();
        }
        finally
        {
            Marshal.Release(innerInterface);
        }
    }
    //...
}

This architecture allows WinUI components to offer faster rendering, animation support, and higher FPS. Unfortunately, each action within a component requires WinRT interop, which is slow. The following table demonstrates the dramatic (negative) effects of WinRT interop on dependency properties:

Action WPF, ns WinUI, ns
Get 19 2023
Set 135 4272
Set with property change handler 139 20431
Set to the same value 89 4150
Set TextBlock.Text 253 725
Set Border.Background 248 2412

You can learn more about this issue in the following GitHub discussion: Dependency property is much slower in WinUI 3 than in WPF.

DevExpress Data Grid Performance Optimizations

Though WinUI’s architecture complicates our job as a component vendor, we have taken a series of steps to minimize WinUI’s negative impact on rendering performance. Typically, complex WinUI components consist of multiple visual elements. With v21.2, we minimized the number of internal elements and reduced the number of dependency properties.

These changes produced significant (and beneficial results). As you can see in the chart below, our WinUI Data Grid is now very fast (we think it’s the fasted WinUI Data Grid on the market today)

Startup Performance

Startup Performance

Scrolling Performance

Scrolling Performance

With v22.1 the control used to display cells (CellControl) is inherited from the standard Panel class and all parts are created internally. The layout is determined via Measure and Arrange methods. Additionally, the CellControl class doesn’t have custom dependency properties and you can’t customize it. The same optimization was made in the control used to represent rows (RowControl). We also enhanced our virtualization mechanism so that cell DataContexts are not modified during scroll operations.

These changes helped produce a breakthrough in terms of performance. Unfortunately, creating controls internally reduced customization options (to a certain degree). To compensate for this, we added APIs to improve cell/row customization (make it simple and flexible). For example, the RowStyleSettings allows you to customize static row appearance settings:

<dxg:GridControl.RowStyleSettings> 
      <dxg:RowStyleSettings Background="LightGray" 
                              SelectedBackground="PaleVioletRed"  
                              FocusedBackground="LightBlue"  
                              FocusedSelectedBackground="Orange"  
                              HoverBackground="LightGreen"  
                              FocusedBorderBrush="Red"  
                              FocusedBorderThickness="1"  
                              FocusedCornerRadius="5"/> 
</dxg:GridControl.RowStyleSettings>

To change row appearance (based on data), you can use Conditional Formatting. We are also working on creating properties to customize different row sections and offer you maximum development flexibility.

What's Next?

Performance: Our latest release already addresses major performance challenges, but we still see room for improvement. For example, if you add standard controls such as CheckBox or ProgressBar to cells, you may notice a slight decrease in responsiveness. This happens because controls change their state frequently during scrolling and cause WinRT interop. We expect to create optimized grid cells controls (such as CheckBoxes and ProgressBars) this year.
More Controls – Extended Features: We will release additional UI controls and address a broader range of usage scenarios in 2022. We expect to publish a roadmap later this month. Please stay tuned for more information in this regard.

Your Feedback Matters

Should you have any questions about our WinUI product line, or if you’d like to discuss your WinUI development needs with us, please comment below or create a new DevExpress Support Center ticket.

Free DevExpress Products – Get Your Copy Today

The following free DevExpress product offers remain available. Should you have any questions about the free offers below, please submit a ticket via the DevExpress Support Center at your convenience. We’ll be happy to follow-up.
Peter Drier 2
Peter Drier
Great to see DX leading and pushing MS to fix such important performance problems.  Thx Alex.
24 January 2022
Lutz Fritsche
Lutz Fritsche
When should we think about moving our DX WPF implementation to WinUI? Including for example DXGrid in server mode and DockLayoutManager.

(Please move this question to a better place or forum if one exists.)

24 January 2022
CRM-84c1ddc4-d6b1-4a7e-b2d8-53440b611cc4
jiri trunkat
Love to see people caring about speed. The Windows 10 UI libraries are so slow. Just check the default Windows 10 settings application UI etc.
Newer computers are getting faster but newer UIs are getting slower. Except DevExpress.
24 January 2022
ch.lee
ch.lee

I appreciate your efforts to improve performance.

I use winform dockmanager. Are there any replaceable controls in winui?

24 January 2022
Customer45398
Vojtěch Frnoch

Great post, thank you. Please consider writing a head to head comparison with WPF. 

From what I gathered WinUI still seems to be an order of magnitude slower making it impossible to switch. WPF already doesn't feel very responsive in complex scenarios.



25 January 2022
Alexander Rus (DevExpress Support)
Alexander Russkov (DevExpress)

@Lutz, @ch.lee

While not available at this time, we will definitely consider Server Mode and Docking for future implementation. Please feel free to create a ticket in the Support Center - we will be happy to discuss your requirements and address migration concerns.

 

@Vojtěch

Although the WinUI platform still has certain bottlenecks, our goal is to minimize their impact to DevExpress users. Our WinUI Data Grid already performs well when compared to our WPF Data Grid and we will continue to optimize it. As for WPF components, we also expect to enhance performance in 2022.

 

25 January 2022

Please login or register to post comments.