开发人员在使用WPF做图形界面的时候,通常都希望能有一个高效的利用率。在这里我们就为大家介绍一下有关WPF性能优化的几种方法。#t#
WPF性能优化一、Rendering Tier
1. 根据硬件配置的不同,WPF采用不同的Rendering Tier做渲染。下列情况请特别注意,因为在这些情况下,即使是处于Rendering Tier 2的情况下也不会硬件加速。(不全,其余请查阅SDK)
Bitmap effects, Printed content, Tiled content that uses TileBrush, Layered windows.
下列情况为Layered window: 1. WindowStyle = none, 2.AllowsTransparency = true, 3.Background = Transparent.
WPF性能优化二、布局和设计
1.尽量多使用Canvas等简单的布局元素,少使用Grid或者StackPanel等复杂的,越复杂性能开销越大。
2.建立逻辑树或者视觉树的时候,遵循Top-Down的原则。示例代码如下:
- C#
- private void OnBuildTreeTopDown
(object sender, RoutedEventArgs e) - {
- TextBlock textBlock = new TextBlock();
- textBlock.Text = "Default";
- DockPanel parentPanel = new DockPanel();
- DockPanel childPanel;
- myCanvas.Children.Add(parentPanel);
- myCanvas.Children.Add(textBlock);
- for (int i = 0; i < 150; i++)
- {
- textBlock = new TextBlock();
- textBlock.Text = "Default";
- parentPanel.Children.Add(textBlock);
- childPanel = new DockPanel();
- parentPanel.Children.Add(childPanel);
- parentPanel = childPanel;
- }
- }
WPF性能优化三、图像
1. 对Image做动画处理的时候(如调整大小等),可以使用这条语句RenderOptions.SetBitmapScalingMode(MyImage,BitmapScalingMode.LowQuality),以改善性能。
2. 用TileBrush的时候,可以CachingHint。
WPF性能优化四、对象行为
1.访问CLR对象和CLR属性的效率会比访问DependencyObject/DependencyProperty高。注意这里指的是访问,不要和前面的绑定混淆了。但是,把属性注册为DependencyProperty会有很多的优点:比如继承、数据绑定和Style。所以有时候我们可以在实现DependencyProperty的时候,利用缓存机制来加速访问速度:看下面的缓存例子:
public static readonly Dependency
Property MagicStringProperty =
DependencyProperty.Register(
"MagicString", typeof(string),
typeof(MyButton), new PropertyMetadata
(new PropertyInvalidatedCallback
(OnMagicStringPropertyInvalidated),
new GetValueOverride(MagicStringGet
ValueCallback)));
private static void OnMagicString
PropertyInvalidated(DependencyObject d)
{
// 将缓存的数据标识为无效
((MyButton)d)._magicStringValid = false;
}
private static object MagicString
GetValueCallback(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;
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
另外,因为注册的DependencyProperty在默认是不可继承的,如果需要继承特性,也会降低DependencyProperty值刷新的效率。注册DependencyProperty属性时,应该把DefaultValue传递给Register方法的参数来实现默认值的设置,而不是在构造函数中设置。
WPF性能优化五、应用程序资源
1. 在自定义控件,尽量不要在控件的ResourceDictionary定义资源,而应该放在Window或者Application级。因为放在控件中会使每个实例都保留一份资源的拷贝。
2. 尽量使用Static Resources,但不能盲目使用。
WPF性能优化六、文本
1. 文字少的时候用TextBlock或者label,长的时候用FlowDocument.
2. 使用元素TextFlow和TextBlock时,如果不需要TextFlow的某些特性,就应该考虑使用TextBlock,因为它的效率更高。
3. 在TextFlow中使用UIElement(比如TextBlock)所需的代价要比使用TextElement(比如Run)的代价高.在FlowDocument中尽量避免使用TextBlock,要用Run替代。代码如下:
< FlowDocument>
< !-- Text content within
a Run (more efficient). -->
< Paragraph>
< Run>Line one< /Run>
< /Paragraph>
< !-- Text content within
a TextBlock (less
efficient). -->
< Paragraph>
< TextBlock>Line two
< /TextBlock>
< /Paragraph>
< /FlowDocument>
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
4. 在TextBlock中显式的使用Run命令比不使用Run命名的代码要高。
< !-- Run is used to set
text properties. -->
< TextBlock>
< Run FontWeight="Bold">
Hello, world< /Run>
< /TextBlock>
< !-- TextBlock is used
to set text properties,
which is more efficient. -->
< TextBlock FontWeight=
"Bold">
Hello, world
< /TextBlock>
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
5. 把Label(标签)元素的ContentProperty和一个字符串(String)绑定的效率要比把字符串和TextBlock的Text属性绑定的效率低。因为Label在更新字符串是会丢弃原来的字符串,全部重新显示内容。如果字符串不需要更新,用Label就无所谓性能问题。
6. 在TextBlock块使用HyperLinks时,把多个HyperLinks组合在一起效率会更高。
< !-- Hyperlinks in separate
TextBlocks. -->
< TextBlock>
< Hyperlink TextDecorations=
"None" NavigateUri="http:
//www.msn.com">MSN Home
< /Hyperlink>
< /TextBlock>
< TextBlock Text=" | "/>
< TextBlock>
< Hyperlink TextDecorations=
"None" NavigateUri="http:
//my.msn.com">My MSN< /Hyperlink>
< /TextBlock>
< !-- Hyperlinks combined
in the same TextBlock. -->
< TextBlock>
< Hyperlink TextDecorations=
"None" NavigateUri="http:
//www.msn.com">MSN Home< /Hyperlink>
< Run Text=" | " />
< Hyperlink TextDecorations=
"None" NavigateUri="http:
//my.msn.com">My MSN< /Hyperlink>
< /TextBlock>
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
7. 显示超链接的时候,尽量只在IsMouseOver为True的时候显示下划线,一直显示下划线的代码高很多
8. 尽量不使用不必要的字符串连接。
WPF性能优化七、数据绑定
1.在使用数据绑定的过程中,如果绑定的数据源是一个CLR对象,属性也是一个CLR属性,那么在绑定的时候对象CLR对象所实现的机制不同,绑定的效率也不同。
A、数据源是一个CLR对象,属性也是一个CLR属性。对象通过TypeDescriptor/PropertyChanged模式实现通知功能。此时绑定引擎用TypeDescriptor来反射源对象。效率***。
B、数据源是一个CLR对象,属性也是一个CLR属性。对象通过INotifyPropertyChanged实现通知功能。此时绑定引擎直接反射源对象。效率稍微提高。
C、数据源是一个DependencyObject,而且属性是一个DependencyProperty。此时不需要反射,直接绑定。效率***。
2.当一个CLR对象很大时,比如有1000个属性时,尽量把这个对象分解成很多很小的CLR对象。比如分成1000个只有一个属性的CLR对象。
3. 当我们在列表(比如ListBox)显示了一个CLR对象列表(比如List)时,如果想在修改List对象后,ListBox也动态的反映这种变化。此时,我们应该使用动态的ObservableCollection对象绑定。而不是直接的更新ItemSource。两者的区别在于直接更新ItemSource会使WPF抛弃ListBox已有的所有数据,然后全部重新从List加载。而使用ObservableCollection可以避免这种先全部删除再重载的过程,效率更高。
4. 尽量绑定IList而不是IEnumerable到ItemsControl。
WPF性能优化八、其它性能建议
1. 如果需要修改元素的Opacity属性,***修改一个Brush的属性,然后用这个Brush来填充元素。因为直接修改元素的Opacity会迫使系统创建一个临时的Surface
2. 用NavigationWindow的时候,尽量Update the client area by object,而不是URI
3. 尽量不要使用ScrollBarVisibility=Auto