邳州建设局网站,北京 设计网站,吴江公司注册,美的公司网站建设的目的WPF 绘制对齐像素的清晰显示的线条 原文:WPF 绘制对齐像素的清晰显示的线条版权声明#xff1a;本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布#xff0c;但务必保留文章署名吕毅#xff08;包含链接#xff1a;h… WPF 绘制对齐像素的清晰显示的线条 原文:WPF 绘制对齐像素的清晰显示的线条 版权声明本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布但务必保留文章署名吕毅包含链接http://blog.csdn.net/wpwalter/不得用于商业目的基于本文修改后的作品务必以相同的许可发布。如有任何疑问请与我联系walter.lvqq.com。 https://blog.csdn.net/WPwalter/article/details/78858762 此前有小伙伴询问我为何他 1 像素的线条显示发虚然后我告诉他是“像素对齐”的问题然而他设置了各种对齐像素的属性依旧没有作用。于是我对此进行了一系列试验对 WPF 像素对齐的各种方法进行了一次总结。此后在 StackOverflow 中我回答了 graphics - WPF DrawingContext seems ignore SnapToDevicePixels - Stack Overflow 问题。 阅读本文我们将了解解决 WPF 像素对齐的四种方法以及其各自的适用范围和副作用。 为什么要做像素对齐 看线条这是 3 像素的线条 然而论其原因就是因为我们屏幕太渣~哦~不是因为绘制的线条没有与屏幕像素对齐具体来说是视觉对象Visual的位置不在整数像素上或尺寸不是整数像素。而与此同时屏幕的点距又太大以至于我们看出来绘制的线条和屏幕像素之间的差异。 然而为什么 WPF 不默认为我们对齐像素呢这是因为要对齐像素必定带来尺寸上的偏差这是绘制尺寸精度和最终呈现效果之间的平衡。在 MacBook、Surface Pro 这些高档显示屏上根本不用管这样的平衡问题但在渣渣显示器上微软把这种平衡的控制交给了应用的开发者。 处理像素对齐的四种方法 方法一布局取整 UseLayoutRounding 实际效果是 根本就不起作用 事实上我们从 .NET Framework 源码可以得知UseLayoutRounding 实际只处理 UI 元素对自己子级控件的布局取整。一旦整棵布局树种有任何一个不是整数或者 DPI 相乘后不是整数那么就依然没有解决问题。 方法二对齐设备像素 SnapsToDevicePixels 这是一个会沿着逻辑树继承的属性只要最顶层设置了这个属性里面的元素都会具备此特性。不过他只处理矩形的渲染也就是说只对 Border Rectangle 这些类型的元素生效其他的包括自己写的元素基本都是不管用的。 它有一个好处是像素对齐的情况下同时能够保证显示不足或超过 1 像素时也能带一点儿透明或者超过一点像素。 方法三使用 DrwingContext 绘制并配合 GuidelineSet 如果自己处理绘制则可以在 OnRender 方法中使用 DrawingContext 来绘制各种各样的形状。DrawingContext 有方法 PushGuidelineSet而 PushGuidelineSet 就是用来处理对齐的。 以下是四种不同方式的对齐效果对比其中上面一半是直接对齐即绘制过程是紧贴着的下面一半则是多个部分带上一点偏移即并不是紧贴 ▲ 看不清的可以考虑方法看 于是要想像素对齐必须 布局或绘制时UI 元素之间一点偏移或空隙都不能有一点都不行SnapsToDevicePixels 和 GuidelineSet 在实际对齐中有效而 UseLayoutRounding 就是在逗你GuidelineSet 的使用可以参考我在 StackOverflow 上的回答graphics - WPF DrawingContext seems ignore SnapToDevicePixels - Stack Overflow。 以下是我编写的用于辅助绘制对齐线条的扩展方法 public static class SnapDrawingExtensions
{public static void DrawSnappedLinesBetweenPoints(this DrawingContext dc,Pen pen, double lineThickness, params Point[] points){var guidelineSet new GuidelineSet();foreach (var point in points){guidelineSet.GuidelinesX.Add(point.X);guidelineSet.GuidelinesY.Add(point.Y);}var half lineThickness / 2;points points.Select(p new Point(p.X half, p.Y half)).ToArray();dc.PushGuidelineSet(guidelineSet);for (var i 0; i points.Length - 1; i i 2){dc.DrawLine(pen, points[i], points[i 1]);}dc.Pop();}
} 注意添加到 GuidelineSet 的尺寸不需要是整数也不需要计算对齐屏幕的位置只需要随便指定一个值即可但相邻的绘制元素的值需要在 double 级别完全相同多一点少一点都不行。 在 OnRender 中调用它绘制 protected override void OnRender(DrawingContext dc)
{// Draw four horizontal lines and one vertical line.// Notice that even the point X or Y is not an integer, the line is still snapped to device.dc.DrawSnappedLinesBetweenPoints(_pen, LineThickness,new Point(0, 0), new Point(320, 0),new Point(0, 40), new Point(320, 40),new Point(0, 80.5), new Point(320, 80.5),new Point(0, 119.7777), new Point(320, 119.7777),new Point(0, 0), new Point(0, 120));
} 方法四RenderOptions.EdgeMode 这是纯渲染级别的附加属性对所有 UI 元素有效。这个属性很神奇一旦设置元素就再也不会出现模糊的边缘了一定是硬像素边缘。不足半像素的全部删掉超过半像素的变为 1 个像素。 以为它可以解决问题——Too young, too simple. 你希望能够绘制 1 像素的线条实际上它会让你有时看得见 1 像素线条有时看的是 2 像素线条有时居然完全看不见 如果你都作用对象上还有其它视觉对象它们也会一并变成了“硬边缘”是可以看得见一个个像素的边缘。 各种方法适用范围总结 如果画粗线条粗边框那么 RenderOptions.EdgeMode 最适合了因为设置起来最方便可以设置到所有的 UI 元素上。由于边框很粗所以多一个少一个像素用户也注意不到。如果是画细边框那么使用 Border 配合 SnapsToDevicePixels 可以解决无论是 0.8 像素还是 1.0 像素1.2 像素都能在准确地显示其粗细的基础之上还保证像素对齐。如果图形比较复杂比如绘制表格或者其它各种交叉了线条的图形那么使用 DrawingContext 绘制并设置 GuidelineSet 对齐。如果窗口非常简单既没有缩放UI 元素也不多可以考虑使用 UseLayoutRounding 碰碰运气万一界面简单到只需要整数对齐就够了呢特别说明上面四种方法不足与应对所有的像素对齐情况如果还是没办法对齐……节哀把……我们一起找偏方…… posted on 2018-09-21 22:03 NET未来之路 阅读(...) 评论(...) 编辑 收藏 转载于:https://www.cnblogs.com/lonelyxmas/p/9688697.html