WPF Grid 绘制网格线
时间:2021-07-14
本文章向大家介绍WPF Grid 绘制网格线,主要包括WPF Grid 绘制网格线使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
WPF Grid 中 有一个ShowGridLines, 通常这个只用于测试、设计等场合,而且是虚线,无法定制,本文参考ShowGridLines的实现方式,添加了两个依赖属性,可以自行定制网格线,并控制其显示行为。
1 public class TestGrid : Grid 2 { 3 public static DependencyProperty ShowGridBordersProperty = DependencyProperty.Register(nameof(ShowGridBorders), typeof(bool), typeof(TestGrid ), new PropertyMetadata(ShowGridBordersChanged)); 4 public static DependencyProperty GridBorderPenProperty = DependencyProperty.Register(nameof(GridBorderPen), typeof(Pen), typeof(TestGrid), new PropertyMetadata(GridBorderPenChanged)); 5 private GridBordersRenderer _gridBordersRenderer; 6 /// <summary> 7 /// 显示边框笔线 8 /// </summary> 9 public bool ShowGridBorders 10 { 11 get 12 { 13 return (bool)GetValue(ShowGridBordersProperty); 14 } 15 set 16 { 17 SetValue(ShowGridBordersProperty, value); 18 } 19 } 20 /// <summary> 21 /// Grid 边框笔线 22 /// </summary> 23 public Pen GridBorderPen 24 { 25 get 26 { 27 return (Pen)GetValue(GridBorderPenProperty); 28 } 29 set 30 { 31 SetValue(GridBorderPenProperty, value); 32 } 33 } 34 35 protected override int VisualChildrenCount => base.VisualChildrenCount + (_gridBordersRenderer != null ? 1 : 0); 36 37 protected override Visual GetVisualChild(int index) 38 { 39 if (index == base.VisualChildrenCount) 40 { 41 if (_gridBordersRenderer == null) 42 { 43 throw new ArgumentOutOfRangeException("index", index, "超出索引范围"); 44 } 45 return _gridBordersRenderer; 46 } 47 return base.GetVisualChild(index); 48 } 49 protected override Size ArrangeOverride(Size arrangeSize) 50 { 51 Size size = base.ArrangeOverride(arrangeSize); 52 GridBordersRenderer gridBordersRenderer = EnsureGridBordersRenderer(); 53 if (gridBordersRenderer != null) 54 { 55 gridBordersRenderer.UpdateRenderBounds(size); 56 } 57 return size; 58 } 59 60 private GridBordersRenderer EnsureGridBordersRenderer() 61 { 62 if (ShowGridBorders && _gridBordersRenderer == null) 63 { 64 _gridBordersRenderer = new GridBordersRenderer(); 65 _gridBordersRenderer.BorderPen = GridBorderPen; 66 AddVisualChild(_gridBordersRenderer); 67 } 68 if (!ShowGridBorders && _gridBordersRenderer != null) 69 { 70 RemoveVisualChild(_gridBordersRenderer); 71 _gridBordersRenderer = null; 72 } 73 return _gridBordersRenderer; 74 } 75 private static void ShowGridBordersChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 76 { 77 Grid grid = d as Grid; 78 grid.InvalidateVisual(); 79 } 80 81 private static void GridBorderPenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 82 { 83 TestGrid grid = d as TestGrid; 84 if (grid._gridBordersRenderer != null) 85 { 86 grid._gridBordersRenderer.BorderPen = (Pen)e.NewValue; 87 grid.InvalidateVisual(); 88 } 89 } 90 91 class GridBordersRenderer : DrawingVisual 92 { 93 private Pen borderPenField; 94 public Pen BorderPen 95 { 96 get 97 { 98 if (borderPenField == null) 99 { 100 borderPenField = new Pen(Brushes.Gray, 0.1); 101 borderPenField.StartLineCap = PenLineCap.Square; 102 borderPenField.EndLineCap = PenLineCap.Square; 103 } 104 return borderPenField; 105 } 106 set 107 { 108 borderPenField = value; 109 } 110 } 111 public void UpdateRenderBounds(Size boundsSize) 112 { 113 using (DrawingContext drawingContext = RenderOpen()) 114 { 115 TestGrid grid = VisualTreeHelper.GetParent(this) as TestGrid; 116 if (grid != null && grid.ShowGridBorders) 117 { 118 var rowDefinitions = DefinitionsU(grid); 119 for (int i = 1; i < rowDefinitions.Length; i++) 120 { 121 double xOffset = FinalOffset(rowDefinitions[i]); 122 DrawGridLine(drawingContext, xOffset, 0.0, xOffset, boundsSize.Height); 123 } 124 var columnDefinitions = DefinitionsV(grid); 125 for (int j = 1; j < columnDefinitions.Length; j++) 126 { 127 double yOffset = FinalOffset(columnDefinitions[j]); 128 DrawGridLine(drawingContext, 0.0, yOffset, boundsSize.Width, yOffset); 129 } 130 DrawGridRectangle(drawingContext, 0.0, 0.0, boundsSize.Width, boundsSize.Height); 131 } 132 } 133 } 134 135 private void DrawGridLine(DrawingContext drawingContext, double startX, double startY, double endX, double endY) 136 { 137 Point point = new Point(startX, startY); 138 Point point2 = new Point(endX, endY); 139 drawingContext.DrawLine(BorderPen, point, point2); 140 } 141 142 private void DrawGridRectangle(DrawingContext drawingContext, double startX, double startY, double endX, double endY) 143 { 144 Rect rect = Rect.Parse($"{startX},{startY},{endX},{endY}"); 145 drawingContext.DrawRectangle(null, BorderPen, rect); 146 } 147 148 private DefinitionBase[] DefinitionsU(Grid grid) 149 { 150 DefinitionBase[] definitions = (DefinitionBase[])typeof(Grid).InvokeMember("DefinitionsU", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetProperty, Type.DefaultBinder, grid, null); 151 return definitions; 152 } 153 154 private DefinitionBase[] DefinitionsV(Grid grid) 155 { 156 DefinitionBase[] definitions = (DefinitionBase[])typeof(Grid).InvokeMember("DefinitionsV", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetProperty, Type.DefaultBinder, grid, null); 157 return definitions; 158 } 159 private double FinalOffset(DefinitionBase definition) 160 { 161 return (double)definition.GetType().InvokeMember("FinalOffset", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetProperty, Type.DefaultBinder, definition, null); 162 } 163 } 164 }
第一篇文章,多余话不太会说,看代码吧。
原文地址:https://www.cnblogs.com/FengKaKa/p/15010495.html
- (五)如何编写高性能日志
- Scala之偏函数Partial Function
- (六)关于网络编程的一些实用技巧和细节
- 快学Scala习题答案汇总
- (八)高性能服务器架构设计总结1——以flamigo服务器代码为例
- (八)高性能服务器架构设计总结2——以flamigo服务器代码为例
- Scala集合练习题
- 机器学习(10)之趣味案例理解朴素贝叶斯
- Spart DataSet数据集
- (八)高性能服务器架构设计总结3——以flamigo服务器代码为例
- (八)高性能服务器架构设计总结4——以flamigo服务器代码为例
- SQL员工部门表综合查询60题
- 如何对Scala中集合(Collections)进行排序
- 小白教程——安装和使用PyCharm
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Java基础知识三问—百度真题
- 访问权限导致toString返回空BUG分享
- 基于 Spring Boot 的在线考试系统
- Redis系列:高可用哨兵方案部署
- linux或windows环境下pytorch的安装与检查验证(解决runtimeerror问题)
- Linux 查看历史命令并执行的方法
- 在 awk 中使用循环
- 移植busybox构建最小根文件系统的步骤详解
- Linux中的screen命令使用详解
- Mysql4种方式避免重复插入数据!
- 手撕RTSP协议系列(3)——sdp格式详解
- Linux tee命令使用详解
- 简单了解Linux性能监控命令free
- 在CentOS 8上安装htop的教程
- Ubuntu16.04.5LTS安装SVN的过程