性能和UI渲染速度仍然是DevExpress WinUI优先级列表的收尾,本文描述在使用WinUI时遇到的性能挑战以及技术团队为解决这些问题所做的工作,同时还将展示如何为Microsoft的新WinUI平台创建最快的数据网格。
WinUI性能瓶颈
首先回顾一下WinUI平台是如何构建的,以及与其前身(WPF和 WinForms)的架构差异。在WPF和 WinForms中,组件及其核心逻辑在标准.NET库中实现,例如基本WPF类(如 DependencyObject)在 .NET 中完全实现,您始终可以看到当依赖项属性更改时执行的逻辑,非托管代码仅用于 UI 呈现和用户交互(使用 Windows API 调用实现)。
在WinUI中,所有内部逻辑都是使用原生WinRT组件实现的,Windows App SDK仅为这些组件提供 .NET 封装器。DependencyObject 类初始化映射到 IDependencyObject 接口的 WinRT 对象,并在调用依赖属性设置器或获取器时使用此对象:
[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); } } //... }
这种架构允许 WinUI 组件提供更快的渲染、动画支持和更高的 FPS。不幸的是,组件中的每个操作都需要 WinRT 互操作,这很慢。 下表展示了 WinRT 互操作对依赖属性的显着(负面)影响:
DevExpress数据网格性能优化
尽管 WinUI 的架构使组件供应商的工作变得复杂,但我们已经采取了一系列措施来尽量减少 WinUI 对渲染性能的负面影响。 通常,复杂的 WinUI 组件由多个可视元素组成。在 v21.2 中,我们最大限度地减少了内部元素的数量并减少了依赖属性的数量。
这些变化产生了显着(和有益的结果),如下图所示,WinUI 数据网格现在非常快(我们认为它是当今市场上快速的 WinUI 数据网格):
启动性能
滚动性能
在v22.1中用于显示单元格的控件 (CellControl) 继承自标准 Panel 类,所有部件均在内部创建,布局是通过Measure和Arrange方法确定的。此外CellControl 类没有自定义依赖属性,您无法对其进行自定义。 在用于表示行的控件 (RowControl) 中进行了相同的优化。 我们还增强了虚拟化机制,以便在滚动操作期间不会修改单元格数据上下文。
这些变化有助于在性能方面取得突破,不过在内部创建控件会减少自定义选项(在一定程度上)。 为了弥补这一点,我们添加了 API 来改进单元格/行的自定义(使其简单灵活)。 例如,RowStyleSettings允许您自定义静态行外观设置:
<dxg:GridControl.RowStyleSettings> <dxg:RowStyleSettings Background="LightGray" SelectedBackground="PaleVioletRed" FocusedBackground="LightBlue" FocusedSelectedBackground="Orange" HoverBackground="LightGreen" FocusedBorderBrush="Red" FocusedBorderThickness="1" FocusedCornerRadius="5"/> </dxg:GridControl.RowStyleSettings>
要更改行外观(基于数据),您可以使用条件格式,技术团队还致力于创建属性以自定义不同的行部分并为您提供最大的开发灵活性。
DevExpress WPF拥有120+个控件和库,将帮助您交付满足甚至超出企业需求的高性能业务应用程序。通过DevExpress WPF能创建有着强大互动功能的XAML基础应用程序,这些应用程序专注于当代客户的需求和构建未来新一代支持触摸的解决方案。 无论是Office办公软件的衍伸产品,还是以数据为中心的商业智能产品,都能通过DevExpress WPF控件来实现。
DevExpress技术交流群6:600715373 欢迎一起进群讨论