一、目的:介绍一下WPF中Grid显示网格线的几种方式
二、几种方式
1、重写OnRender绘制网格线(推荐)
效果如下:
实现方式如下:
cs
public class LineGrid : Grid
{
private readonly Pen _pen;
public LineGrid()
{
_pen = new Pen(SystemColors.ActiveBorderBrush, 1);
_pen.Freeze();
}
protected override void OnRender(DrawingContext dc)
{
base.OnRender(dc);
foreach (RowDefinition item in this.RowDefinitions)
{
dc.DrawLine(_pen, new Point(0, item.Offset), new Point(this.ActualWidth, item.Offset));
}
dc.DrawLine(_pen, new Point(0, this.ActualHeight), new Point(this.ActualWidth, this.ActualHeight));
foreach (ColumnDefinition item in this.ColumnDefinitions)
{
dc.DrawLine(_pen, new Point(item.Offset, 0), new Point(item.Offset, this.ActualHeight));
}
dc.DrawLine(_pen, new Point(this.ActualWidth, 0), new Point(this.ActualWidth, this.ActualHeight));
}
}
XML
<local:LineGrid Margin="50">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="50" />
<RowDefinition Height="50" />
<RowDefinition Height="50" />
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<TextBlock
Grid.Row="0"
Grid.RowSpan="2"
Grid.Column="5"
Margin="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Background="White"
Text="LineGrid" />
<Label
Margin="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"
Background="White"
Content="Center"
FontSize="50" />
</local:LineGrid>
**优点:**通过OnRender绘制复杂度低,性能较好
**缺点:**需要单独定义LineGrid类重写OnRender ,但相对来说实现比较简单,复用性比较高
2、使用ShowGridLines属性
效果如下:
实现代码
XML
<Grid Margin="50" ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="50" />
<RowDefinition Height="50" />
<RowDefinition Height="50" />
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<TextBlock
Grid.Row="0"
Grid.RowSpan="2"
Grid.Column="5"
Margin="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Background="White"
Text="LineGrid" />
<Label
Margin="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"
Background="White"
Content="Center"
FontSize="50" />
</Grid>
**优点:**Grid自带功能,直接设置 ShowGridLines="True"即可
**缺点:**样式固定且单一,一般来说是不能满足需求
3、使用Adorner绘制
效果如下:
实现代码:
定义Adorner
cs
public class GridLineAdorner : Adorner
{
public GridLineAdorner(UIElement adornedElement) : base(adornedElement)
{
}
protected override void OnRender(DrawingContext dc)
{
base.OnRender(dc);
Grid grid = this.AdornedElement as Grid;
if (grid == null)
return;
Pen pen = new Pen(SystemColors.HighlightBrush, 1);
foreach (RowDefinition item in grid.RowDefinitions)
{
dc.DrawLine(pen, new Point(0, item.Offset), new Point(this.ActualWidth, item.Offset));
}
dc.DrawLine(pen, new Point(0, grid.ActualHeight), new Point(this.ActualWidth, this.ActualHeight));
foreach (ColumnDefinition item in grid.ColumnDefinitions)
{
dc.DrawLine(pen, new Point(item.Offset, 0), new Point(item.Offset, this.ActualHeight));
}
dc.DrawLine(pen, new Point(this.ActualWidth, 0), new Point(this.ActualWidth, this.ActualHeight));
}
}
(注:这部分目前没有实现Rowspan和Columnspan网线的遮挡,有需求的可以使用PushClip方式实现)
Xaml中添加代码
XML
<AdornerDecorator>
<Grid Margin="50" Loaded="GridLine_Loaded">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="50" />
<RowDefinition Height="50" />
<RowDefinition Height="50" />
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<TextBlock
Grid.Row="0"
Grid.RowSpan="2"
Grid.Column="5"
Margin="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Background="White"
Text="LineGrid" />
<Label
Margin="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"
Background="White"
Content="Center"
FontSize="50" />
</Grid>
</AdornerDecorator>
在Loaded时给Grid添加Adoner
cs
private void GridLine_Loaded(object sender, RoutedEventArgs e)
{
Grid grid = sender as Grid;
GridLineAdorner gridLineAdorner = new GridLineAdorner(grid);
var layer = AdornerLayer.GetAdornerLayer(grid);
layer.Add(gridLineAdorner);
}
**优点:**定义成Adorner复用性比较高
**缺点:**实现和添加相对复杂些,但一劳永逸,也可以把Loaded部分封装成附加属性调用这样就可以不用单独处理事件
4、使用GridLineAttach附加属性,添加Border的方式绘制
效果如下:
实现代码:
定义附加属性
cs
public class GridLineAttach
{
public static bool GetUse(DependencyObject obj)
{
return (bool)obj.GetValue(UseProperty);
}
public static void SetUse(DependencyObject obj, bool value)
{
obj.SetValue(UseProperty, value);
}
public static readonly DependencyProperty UseProperty =
DependencyProperty.RegisterAttached("Use", typeof(bool), typeof(GridLineAttach), new PropertyMetadata(default(bool), OnUseChanged));
static public void OnUseChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Grid grid = d as Grid;
if (grid == null)
return;
bool n = (bool)e.NewValue;
grid.Loaded -= Grid_Loaded;
if (n)
grid.Loaded += Grid_Loaded;
}
private static void Grid_Loaded(object sender, RoutedEventArgs e)
{
Grid grid = sender as Grid;
var controls = grid.Children;
var count = controls.Count;
for (int i = 0; i < count; i++)
{
var item = controls[i] as FrameworkElement;
var border = new Border()
{
BorderBrush = SystemColors.ActiveBorderBrush,
BorderThickness = new Thickness(1)
};
var row = Grid.GetRow(item);
var column = Grid.GetColumn(item);
var rowspan = Grid.GetRowSpan(item);
var columnspan = Grid.GetColumnSpan(item);
Grid.SetRow(border, row);
Grid.SetColumn(border, column);
Grid.SetRowSpan(border, rowspan);
Grid.SetColumnSpan(border, columnspan);
grid.Children.Add(border);
}
}
}
给Grid添加附加属性
XML
<Grid Margin="50" local:GridLineAttach.Use="True">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<TextBlock
Grid.Row="0"
Grid.RowSpan="2"
Grid.Column="5"
Margin="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Background="White"
Text="LineGrid" />
<Label
Margin="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"
Background="White"
Content="Center"
FontSize="50" />
<TextBlock Text="1" Grid.Row="1"/>
</Grid>
**优点:**定义成附加属性复用性比较高
**缺点:**额外添加了Border元素,对于数据量比较大的情况增加了渲染压力
需要了解的知识点
Grid 类 (System.Windows.Controls) | Microsoft Learn
Adorner 类 (System.Windows.Documents) | Microsoft Learn
AdornerLayer 类 (System.Windows.Documents) | Microsoft Learn
AdornerDecorator 类 (System.Windows.Documents) | Microsoft Learn
UIElement.OnRender(DrawingContext) Method (System.Windows) | Microsoft Learn
Grid.ShowGridLines Property (System.Windows.Controls) | Microsoft Learn
Border 类 (System.Windows.Controls) | Microsoft Learn
System.Windows.Controls 命名空间 | Microsoft Learn
控件库 - WPF .NET Framework | Microsoft Learn
XAML概述 - WPF .NET | Microsoft Learn
Windows Presentation Foundation 简介 - WPF .NET | Microsoft Learn
使用 Visual Studio 创建新应用教程 - WPF .NET | Microsoft Learn
源码地址
GitHub - HeBianGu/WPF-ControlDemo: 示例
GitHub - HeBianGu/WPF-ControlBase: Wpf封装的自定义控件资源库
GitHub - HeBianGu/WPF-Control: WPF轻量控件和皮肤库
了解更多
适用于 .NET 8 的 WPF 的新增功能 - WPF .NET | Microsoft Learn
适用于 .NET 7 的 WPF 的新增功能 - WPF .NET | Microsoft Learn
System.Windows.Controls 命名空间 | Microsoft Learn
Sysinternals - Sysinternals | Microsoft Learn
Windows app development documentation - Windows apps | Microsoft Learn
欢迎使用 Expression Blend | Microsoft Learn
https://learn.microsoft.com/zh-cn/dotnet/desktop/wpf/?view=netdesktop-7.0&WT.mc_id=MVP_380318