MSDN上解释了一大堆,二者对比来看,并不能发现什么明显的区别,微软爸爸也不知道多给写图文实例。经过几个小时的摸索,现得到以下共同点和不同点,仅供参考:
共同点
- 默认值都是false,如果设置到root元素上,则child元素也自动使用同样设置。
- 都是为了解决wpf元素边缘模糊的问题(如下)。
wpf界面元素呈现时为了看起来更平滑一点,是有抗锯齿效果的,抗锯齿效果就会导致边缘模糊。举个例子来说,边缘是如何模糊的:
假如你有条横线,在界面上show的时候应该正好摆放在上下两个像素点的中间地带,如上图所示。wpf在呈现这条线时,会把上下两边的像素点同时着色(同样适用于左右两边)。到底着的是什么颜色,wpf会根据自己的一套算法之类的东西计算出来。这样就会导致整体看起来跟自己想要的相比,会有点透明度,也会看起来模糊了。
为了解决这个问题,就出现了SnapsToDevicePixels 和UseLayoutRounding,不过UseLayoutRounding是.net 4.0之后的产物,微软也建议在程序中优先使用UseLayoutRounding。二者的默认值都是false。在上图的那个问题中,不管是设置UseLayoutRounding=true还是SnapsToDevicePixels =true,都会解决模糊的问题。貌似没什么区别。
详见微软给出的模糊不清的例子:
1.FrameworkElement.UseLayoutRounding 属性
2.Pixel Snapping in WPF Applications
其实可见二者区别不大,给出的例子都只是换了换文字:
不同点
- 二者最大的不同点,其实MSDN上已经讲了:UseLayoutRounding是在during layout的时候生效的,而SnapsToDevicePixels是在during rendering的时候生效的
当layout已经呈现完毕,用UseLayoutRounding所修饰元素的像素对齐样式都已经固定,不依元素位置的变动而动态调整。而SnapsToDevicePixels因为是在render的时候生效的,所以它所修饰的元素 的位置如果发生改变的话,它的像素对齐样式是会改变的。可见下图:
这里是5个close的小图标,width和height设置的都是14,原图是72x72像素的,用放大镜放大到600%。
1号:SnapsToDevicePixels=false
2号:SnapsToDevicePixels=true
3号:UseLayoutRounding=false
4号:UseLayoutRounding=true
5号:UseLayoutRounding=false,SnapsToDevicePixels=false
当你拖动window的边框改变window的大小时,这几个图标是上下移动,你会发现除了4号的样式是固定不变的(注意观察内部的白色叉号),其他几个的样式都在动态变化。
注意观察2号的头部,在某个像素位置与其他的相比是少了一部分的(不是等高的)。这就会产生一种不正常的效果,如果你的icon是一个圆形,当把它的宽高设置的比较小时会变成一个正方形或者长方形。
2.从字面意思看UseLayoutRounding有四舍五入取整的意思,而SnapsToDevicePixels没有
用UseLayoutRounding=true修饰一个Grid元素,设置grid的width为100,将grid等分为3列(设置每一列的width为*)。程序运行后可知这三列的ActualWidth里会有两个33和一个34。而如果设置UseLayoutRounding=false或者SnapsToDevicePixels=true,每一列的宽度都会为33.3333333333333,是均分的。
附有一个demo,有二者详细的比较(使用方法:新建解决方案,然后本项目添加进去,运行之后点击ImageWindow按钮。)。
另外,如果你在编码过程中发现设置UseLayoutRounding不管用,那就再设置下SnapsToDevicePixels吧!
参考:
When should I use SnapsToDevicePixels in WPF 4.0?
FrameworkElement.UseLayoutRounding Property
UIElement.SnapsToDevicePixels Property
Pixel Snapping in WPF Applications