示例: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个人主页-哔哩哔哩视频

相关推荐
军训猫猫头1 小时前
20.抽卡只有金,带保底(WPF) C#
ui·c#·wpf
明耀1 小时前
WPF 设置平均布局 如果隐藏的话,能够自动扩展
wpf
晚安苏州14 小时前
WPF DataTemplate 数据模板
wpf
甜甜不吃芥末1 天前
WPF依赖属性详解
wpf
Hat_man_2 天前
WPF制作图片闪烁的自定义控件
wpf
晚安苏州3 天前
WPF Binding 绑定
wpf·wpf binding·wpf 绑定
wangnaisheng3 天前
【WPF】RenderTargetBitmap的使用
wpf
dotent·4 天前
WPF 完美解决改变指示灯的颜色
wpf
orangapple5 天前
WPF 用Vlc.DotNet.Wpf实现视频播放、停止、暂停功能
wpf·音视频
ysdysyn5 天前
wpf mvvm 数据绑定数据(按钮文字表头都可以),根据长度进行换行,并把换行的文字居中
c#·wpf·mvvm