示例:WPF中Grid显示网格线的几种方式

一、目的:介绍一下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

WPF 介绍 | 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

Reference Source

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

https://github.com/HeBianGu

HeBianGu的个人空间-HeBianGu个人主页-哔哩哔哩视频

相关推荐
九鼎科技-Leo3 小时前
什么是 WPF 中的依赖属性?有什么作用?
windows·c#·.net·wpf
麻花201313 小时前
C#之WPF的C1FlexGrid空间的行加载事件和列事件变更处理动态加载的枚举值
开发语言·c#·wpf
lcintj13 小时前
【WPF】Prism学习(九)
学习·wpf·prism
界面开发小八哥13 小时前
界面控件DevExpress WPF中文教程:网格视图数据布局的列和卡片字段
wpf·界面控件·devexpress·ui开发·用户界面
△曉風殘月〆13 小时前
如何在WPF中嵌入其它程序
wpf
Crazy Struggle13 小时前
功能齐全的 WPF 自定义控件资源库(收藏版)
.net·wpf·ui控件库
shepherd枸杞泡茶1 天前
WPF动画
c#·.net·wpf
lcintj1 天前
【WPF】Prism学习(十)
学习·wpf·prism
wyh要好好学习1 天前
WPF数据加载时添加进度条
ui·wpf
code_shenbing1 天前
跨平台WPF框架Avalonia教程 三
前端·microsoft·ui·c#·wpf·跨平台·界面设计