为WPF的Grid添加网格边框线

在WPF中使用Grid绘制表格的时候,如果元素较多、排列复杂的话,界面会看起来很糟糕,没有层次,这时用网格或边框线分割各元素(标签或单元格)将会是页面看起来整齐有条理。

默认没有边框线的如下图所示:

<Window x:Class="GridLineTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:GridLineTest"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid Width="600" Height="400">
        <Grid.Resources>
            <Style TargetType="TextBlock">
                <Setter Property="FontSize" Value="30"></Setter>
                <Setter Property="HorizontalAlignment" Value="Center"></Setter>
                <Setter Property="VerticalAlignment" Value="Center"></Setter>
            </Style>
        </Grid.Resources>
        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <TextBlock Text="A01" Grid.Row="0" Grid.Column="0"></TextBlock>
        <TextBlock Text="A02" Grid.Row="0" Grid.Column="1"></TextBlock>
        <TextBlock Text="A03" Grid.Row="0" Grid.Column="2"></TextBlock>
        <TextBlock Text="A11" Grid.Row="1" Grid.Column="0"></TextBlock>
        <TextBlock Text="A12" Grid.Row="1" Grid.Column="1"></TextBlock>
        <TextBlock Text="A13" Grid.Row="1" Grid.Column="2"></TextBlock>
        <TextBlock Text="A21" Grid.Row="2" Grid.Column="0"></TextBlock>
        <TextBlock Text="A22" Grid.Row="2" Grid.Column="1"></TextBlock>
        <TextBlock Text="A23" Grid.Row="2" Grid.Column="2"></TextBlock>
    </Grid>
</Window>

一、使用ShowGridLines属性

Grid控件自带属性:ShowGridLines,只需将它设为True即可显示网格线,效果如下:

<Window x:Class="GridLineTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:GridLineTest"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid Width="600" Height="400" ShowGridLines="True">
        <Grid.Resources>
            <Style TargetType="TextBlock">
                <Setter Property="FontSize" Value="30"></Setter>
                <Setter Property="HorizontalAlignment" Value="Center"></Setter>
                <Setter Property="VerticalAlignment" Value="Center"></Setter>
            </Style>
        </Grid.Resources>
        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <TextBlock Text="A01" Grid.Row="0" Grid.Column="0"></TextBlock>
        <TextBlock Text="A02" Grid.Row="0" Grid.Column="1"></TextBlock>
        <TextBlock Text="A03" Grid.Row="0" Grid.Column="2"></TextBlock>
        <TextBlock Text="A11" Grid.Row="1" Grid.Column="0"></TextBlock>
        <TextBlock Text="A12" Grid.Row="1" Grid.Column="1"></TextBlock>
        <TextBlock Text="A13" Grid.Row="1" Grid.Column="2"></TextBlock>
        <TextBlock Text="A21" Grid.Row="2" Grid.Column="0"></TextBlock>
        <TextBlock Text="A22" Grid.Row="2" Grid.Column="1"></TextBlock>
        <TextBlock Text="A23" Grid.Row="2" Grid.Column="2"></TextBlock>
    </Grid>
</Window>

使用ShowGridLines属性的优点是简单,一般用于Grid内部元素排版使用;缺点有:1、无法变更样式,固定是虚线;2、不随单元格合并而改变;3、不会显示最大的外边框线。

二、使用Border添加边框线

适用于行和列较少的情况,不然CV工作量小不了,行号和列号还容易填错。

<Window x:Class="GridLineTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:GridLineTest"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid Width="600" Height="400">
        <Grid.Resources>
            <Style TargetType="TextBlock">
                <Setter Property="FontSize" Value="30"></Setter>
                <Setter Property="HorizontalAlignment" Value="Center"></Setter>
                <Setter Property="VerticalAlignment" Value="Center"></Setter>
            </Style>
            <Style TargetType="Border">
                <Setter Property="BorderBrush" Value="Red"></Setter>
                <Setter Property="BorderThickness" Value="1"></Setter>
            </Style>
        </Grid.Resources>
        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <TextBlock Text="A01" Grid.Row="0" Grid.Column="0"></TextBlock>
        <TextBlock Text="A02" Grid.Row="0" Grid.Column="1"></TextBlock>
        <TextBlock Text="A03" Grid.Row="0" Grid.Column="2"></TextBlock>
        <TextBlock Text="A11" Grid.Row="1" Grid.Column="0"></TextBlock>
        <TextBlock Text="A12" Grid.Row="1" Grid.Column="1"></TextBlock>
        <TextBlock Text="A13" Grid.Row="1" Grid.Column="2"></TextBlock>
        <TextBlock Text="A21" Grid.Row="2" Grid.Column="0"></TextBlock>
        <TextBlock Text="A22" Grid.Row="2" Grid.Column="1"></TextBlock>
        <TextBlock Text="A23" Grid.Row="2" Grid.Column="2"></TextBlock>

        <!--使用Border绘制边框-->
        <Border Grid.Row="0"></Border>
        <Border Grid.Row="1"></Border>
        <Border Grid.Row="2"></Border>
        <Border Grid.Column="0"></Border>
        <Border Grid.Column="1"></Border>
        <Border Grid.Column="2"></Border>
        <Border Grid.Row="1" Grid.Column="1"></Border>
        <Border Grid.Row="1" Grid.Column="2"></Border>
        <Border Grid.Row="2" Grid.Column="1"></Border>
        <Border Grid.Row="2" Grid.Column="2"></Border>
    </Grid>
</Window>

三、使用附加属性添加边框线

TextBlock元素本身并没有行和列的概念,但是可以通过Grid.GetColumn和Grid.SetColumn来附加属性,生成Grid布局。

using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace Helper
{
    public class GridLineHelper
    {

        #region 可以通过propa快捷方式生成下面段代码
        public static bool GetShowBorder(DependencyObject obj)
        {
            return (bool)obj.GetValue(ShowBorderProperty);
        }

        public static void SetShowBorder(DependencyObject obj, bool value)
        {
            obj.SetValue(ShowBorderProperty, value);
        }

        public static readonly DependencyProperty ShowBorderProperty =
            DependencyProperty.RegisterAttached("ShowBorder", typeof(bool), typeof(GridLineHelper), new PropertyMetadata(OnShowBorderChanged));
        #endregion

        //事件处理,需要手工编写,必须是静态方法
        private static void OnShowBorderChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var grid = d as Grid;
            if ((bool)e.OldValue)
            {
                grid.Loaded -= (s, arg) => { };
            }
            if ((bool)e.NewValue)
            {
                grid.Loaded += (s, arg) =>
                {
                    //确定行和列数
                    var rows = grid.RowDefinitions.Count;
                    var columns = grid.ColumnDefinitions.Count;

                    //每个格子添加一个Border进去
                    for (int i = 0; i < rows; i++)
                    {
                        for (int j = 0; j < columns; j++)
                        {
                            var border = new Border() { BorderBrush = new SolidColorBrush(Colors.Gray), BorderThickness = new Thickness(1) };
                            Grid.SetRow(border, i);
                            Grid.SetColumn(border, j);

                            grid.Children.Add(border);
                        }
                    }
                };
            }
        }
    }
}

<Window x:Class="GridLineTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:GridLineTest"
        xmlns:ext="clr-namespace:Helper"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid Width="600" Height="400" ext:GridLineHelper.ShowBorder="True">
        <Grid.Resources>
            <Style TargetType="TextBlock">
                <Setter Property="FontSize" Value="30"></Setter>
                <Setter Property="HorizontalAlignment" Value="Center"></Setter>
                <Setter Property="VerticalAlignment" Value="Center"></Setter>
            </Style>
            <Style TargetType="Border">
                <Setter Property="BorderBrush" Value="Red"></Setter>
                <Setter Property="BorderThickness" Value="1"></Setter>
            </Style>
        </Grid.Resources>
        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <TextBlock Text="A01" Grid.Row="0" Grid.Column="0"></TextBlock>
        <TextBlock Text="A02" Grid.Row="0" Grid.Column="1"></TextBlock>
        <TextBlock Text="A03" Grid.Row="0" Grid.Column="2"></TextBlock>
        <TextBlock Text="A11" Grid.Row="1" Grid.Column="0"></TextBlock>
        <TextBlock Text="A12" Grid.Row="1" Grid.Column="1"></TextBlock>
        <TextBlock Text="A13" Grid.Row="1" Grid.Column="2"></TextBlock>
        <TextBlock Text="A21" Grid.Row="2" Grid.Column="0"></TextBlock>
        <TextBlock Text="A22" Grid.Row="2" Grid.Column="1"></TextBlock>
        <TextBlock Text="A23" Grid.Row="2" Grid.Column="2"></TextBlock>
    </Grid>
</Window>

如果有合并的单元格的情况又该如何处理呢?这时就需要用到Grid.SetRowSpan和Grid.SetColumnSpan来附加属性。

using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace Helper
{
    public class GridLineHelper
    {

        #region 可以通过propa快捷方式生成下面段代码
        public static bool GetShowBorder(DependencyObject obj)
        {
            return (bool)obj.GetValue(ShowBorderProperty);
        }

        public static void SetShowBorder(DependencyObject obj, bool value)
        {
            obj.SetValue(ShowBorderProperty, value);
        }

        public static readonly DependencyProperty ShowBorderProperty =
            DependencyProperty.RegisterAttached("ShowBorder", typeof(bool), typeof(GridLineHelper), new PropertyMetadata(OnShowBorderChanged));
        #endregion

        //事件处理,需要手工编写,必须是静态方法
        private static void OnShowBorderChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var grid = d as Grid;
            string name = grid.Name;
            if ((bool)e.OldValue)
            {
                grid.Loaded -= (s, arg) => { };
            }
            if ((bool)e.NewValue)
            {
                grid.Loaded += (s, arg) =>
                {
                    //根据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 = new SolidColorBrush(Colors.LightGray),
                            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);
                    }
                };
            }
        }
    }
}

<Window x:Class="GridLineTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:GridLineTest"
        xmlns:ext="clr-namespace:Helper"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid Width="600" Height="400" ext:GridLineHelper.ShowBorder="True" x:Name="MyGrid">
        <Grid.Resources>
            <Style TargetType="TextBlock">
                <Setter Property="FontSize" Value="30"></Setter>
                <Setter Property="HorizontalAlignment" Value="Center"></Setter>
                <Setter Property="VerticalAlignment" Value="Center"></Setter>
            </Style>
        </Grid.Resources>
        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <TextBlock Text="A01" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2"></TextBlock>
        <!--<TextBlock Text="A02" Grid.Row="0" Grid.Column="1"></TextBlock>-->
        <TextBlock Text="A03" Grid.Row="0" Grid.Column="2"></TextBlock>
        <TextBlock Text="A11" Grid.Row="1" Grid.Column="0"></TextBlock>
        <TextBlock Text="A12" Grid.Row="1" Grid.Column="1"></TextBlock>
        <TextBlock Text="A13" Grid.Row="1" Grid.Column="2"></TextBlock>
        <TextBlock Text="A21" Grid.Row="2" Grid.Column="0"></TextBlock>
        <TextBlock Text="A22" Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="2"></TextBlock>
        <!--<TextBlock Text="A23" Grid.Row="2" Grid.Column="2"></TextBlock>-->
    </Grid>
</Window>

四、补充

有时需要遍历Grid中的所有元素来做映射等功能,为了方便和减少循环的数据量,会剔除其中的Border元素,可以使用下方行代码实现:

var childrens = this.MyGrid.Children.OfType<UIElement>().ToList().Except(this.MyGrid.Children.OfType<Border>().ToList()).ToList();
相关推荐
芝麻科技1 天前
使用ValueConverters扩展实现枚举控制页面的显示
wpf·prism
笑非不退2 天前
Wpf Image 展示方式 图片处理 显示
开发语言·javascript·wpf
△曉風殘月〆2 天前
在WPF中实现多语言切换的四种方式
wpf·多语言切换
笑非不退2 天前
WPF C# 读写嵌入的资源 JSON PNG JPG JPEG 图片等资源
c#·wpf
He BianGu2 天前
演示:基于WPF的DrawingVisual开发的频谱图和律动图
wpf·示波器·曲线图·频谱分析仪·频谱图·高性能曲线·自绘
笑非不退5 天前
WPF 设计属性 设计页面时实时显示 页面涉及集合时不显示处理 设计页面时显示集合样式 显示ItemSource TabControl等集合样式
wpf
△曉風殘月〆6 天前
WPF中的XAML详解
wpf·xaml
ithouse6 天前
使用WPF实现一个快速切换JDK版本的客户端工具
java·开发语言·wpf
河西石头6 天前
WPF之UI进阶--控件样式与样式模板及词典
ui·wpf·样式·模板·控件样式·样式模板·样式词典
TA远方7 天前
【WPF】桌面程序开发之窗口的用户控件详解
c#·wpf·usercontrol·用户控件·控件属性