WPF性能优化点——出自《IT168》

    在建立漂亮 UI 的同时,我们还需要关注应用程序的性能, WPF 尤其如此。下面从 MS 的文档中总结出了一些有用的性能优化点。在实际编写的过程中,可以参考。这个 Post 非完全原创,是根据一些文档总结出来的。

    1
、建立逻辑树的时候,尽量考虑从父结点到子结点的顺序构建。因为当逻辑树的一个结点发生变化时(比如添加或删除),它的父结点和所有的子结点都会激发 Invalidation 。我们应该避免不必要的 Invalidation

    2
、当我们在列表(比如 ListBox )显示了一个 CLR 对象列表(比如 List )时,如果想在修改 List 对象后, ListBox 也动态的反映这种变 化。此时,我们应该使用动态的 ObservableCollection 对象绑定。而不是直接的更新 ItemSource 。两者的区别在于直接更新 ItemSource 会使 WPF 抛弃 ListBox 已有的所有数据,然后全部重新从 List 加载。而使用 ObservableCollection 可以避 免这种先全部删除再重载的过程,效率更高。

    3
、在使用数据绑定的过程中,如果绑定的数据源是一个 CLR 对象,属性也是一个 CLR 属性,那么在绑定的时候对象 CLR 对象所实现的机制不同,绑定的效率也不同。

    A
、数据源是一个 CLR 对象,属性也是一个 CLR 属性。对象通过 TypeDescriptor/PropertyChanged 模式实现通知功能。此时绑定引擎用 TypeDescriptor 来反射源对象。效率最低。
    B
、数据源是一个 CLR 对象,属性也是一个 CLR 属性。对象通过 INotifyPropertyChanged 实现通知功能。此时绑定引擎直接反射源对象。效率稍微提高。
    C
、数据源是一个 DependencyObject ,而且属性是一个 DependencyProperty 。此时不需要反射,直接绑定。效率最高。

    4
、访问 CLR 对象和 CLR 属性的效率会比访问 DependencyObject/DependencyProperty 高。注意这里指的是访问,不要和 前面的绑定混淆了。但是,把属性注册为 DependencyProperty 会有很多的优点:比如继承、数据绑定和 Style 。所以有时候我们可以在实现 DependencyProperty 的时候,利用缓存机制来加速访问速度:看下面的缓存例子:

public static readonly DependencyProperty MagicStringProperty = DependencyProperty.Register("MagicString", typeof(string), typeof(MyButton), new PropertyMetadata(new PropertyInvalidatedCallback(OnMagicStringPropertyInvalidated),new GetValueOverride(MagicStringGetValueCallback))); private static void OnMagicStringPropertyInvalidated(DependencyObject d) { // 将缓存的数据标识为无效 ((MyButton)d)._magicStringValid = false; } private static object MagicStringGetValueCallback(DependencyObject d) { // 调用缓存的访问器来获取值 return ((MyButton)d).MagicString; } // 私有的CLR访问器和本地缓存 public string MagicString { get { // 在当前值无效时,获取最新的值保存起来 if (!_magicStringValid) { _magicString = (string)GetValueBase(MagicStringProperty); _magicStringValid = true; } return _magicString; } set { SetValue(MagicStringProperty, value); } } private string _magicString; private bool _magicStringValid;

    另外,因为注册的 DependencyProperty 在默认是不可继承的,如果需要继承特性,也会降低 DependencyProperty 值刷新的效 率。注册 DependencyProperty 属性时,应该把 DefaultValue 传递给 Register 方法的参数来实现默认值的设置,而不是在构 造函数中设置。

    5
、使用元素 TextFlow TextBlock 时,如果不需要 TextFlow 的某些特性,就应该考虑使用 TextBlock ,因为它的效率更高。

    6
、在 TextBlock 中显式的使用 Run 命令比不使用 Run 命名的代码要高。

    7
、在 TextFlow 中使用 UIElement (比如 TextBlock )所需的代价要比使用 TextElement (比如 Run )的代价高。

    8
、把 Label (标签)元素的 ContentProperty 和一个字符串( String )绑定的效率要比把字符串和 TextBlock Text 属性 绑定的效率低。因为 Label 在更新字符串是会丢弃原来的字符串,全部重新显示内容。

    9
、在 TextBlock 块使用 HyperLinks 时,把多个 HyperLinks 组合在一起效率会更高。看下面的两种写法,后一种效率高。

A

 

<TextBlock Width="600" > <Hyperlink TextDecorations="None">MSN Home</Hyperlink> </TextBlock> <TextBlock Width="600" > <Hyperlink TextDecorations="None">My MSN</Hyperlink> </TextBlock>

B

<TextBlock Width="600" > <Hyperlink TextDecorations="None">MSN Home</Hyperlink> <Hyperlink TextDecorations="None">My MSN</Hyperlink> </TextBlock>

    10 、任与上面 TextDecorations 有关,显示超链接的时候,尽量只在 IsMouseOver True 的时候显示下划线,一直显示下划线的代码高很多。

    11
、在自定义控件,尽量不要在控件的 ResourceDictionary 定义资源,而应该放在 Window 或者 Application 级。因为放在控件中会使每个实例都保留一份资源的拷贝。

    12
、如果多个元素使用相同的 Brush 时,应该考虑在资源定义 Brush ,让他们共享一个 Brush 实例。

    13
、如果需要修改元素的 Opacity 属性,最后修改一个 Brush 的属性,然后用这个 Brush 来填充元素。因为直接修改元素的 Opacity 会迫使系统创建一个临时的 Surface

    14
、在系统中使用大型的 3D Surface 时,如果不需要 Surface HitTest 功能,请关闭它。因为默认的 HitTest 会占用大量的 CPU 时间进行计算。 UIElement 有应该 IsHitTestVisible 属性可以用来关闭 HitTest 功能。

  依然是浮云。。。

你可能感兴趣的:(WPF性能优化点——出自《IT168》)