惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Y
Y Combinator Blog
有赞技术团队
有赞技术团队
J
Java Code Geeks
H
Hackread – Cybersecurity News, Data Breaches, AI and More
美团技术团队
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Hugging Face - Blog
Hugging Face - Blog
人人都是产品经理
人人都是产品经理
酷 壳 – CoolShell
酷 壳 – CoolShell
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
C
Check Point Blog
博客园 - 【当耐特】
The GitHub Blog
The GitHub Blog
Recent Announcements
Recent Announcements
The Cloudflare Blog
Microsoft Azure Blog
Microsoft Azure Blog
腾讯CDC
Vercel News
Vercel News
IT之家
IT之家
MyScale Blog
MyScale Blog
博客园_首页
Martin Fowler
Martin Fowler
WordPress大学
WordPress大学
罗磊的独立博客

博客园 - 赖仪灵

分享几个简单的WPF控件(代码) 捕捉WPF应用程序中XAML代码解析异常 设置WPF窗口相对于非WPF窗口的位置 上海.NET俱乐部--微软社区巡展VSTS上海专题活动 WPF关于WindowInteropHelper的一个BUG WPF全景体验 最优化WPF 3D性能(基于“Tier-2”硬件) Windows Vista桌面窗口管理器(3) 闲话WPF之二五(WPF中的ControlTemplate [3]) 闲话WPF之二四(WPF中的ControlTemplate [2]) Windows Vista桌面窗口管理器(2) 闲话WPF之二三(WPF中的ControlTemplate [1]) 闲话WPF之二二(WPF中的Style) Windows Vista桌面窗口管理器(1) 闲话WPF之二一(WPF中的数据处理 [3]) 闲话WPF之二十(WPF中的传递事件 [2] ) 闲话WPF之十九(WPF中的传递事件 [1] ) 闲话WPF之十八(WPF中的资源 [4] ) 闲话WPF之十七(WPF中的资源 [3])
闲话WPF之二六(WPF性能优化点)
赖仪灵 · 2007-01-19 · via 博客园 - 赖仪灵

在建立漂亮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功能。