Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

How do I put a border on my grid in C#/WPF?

This is what I would like it to be, but puts a border around the whole thing instead of the grid control I put in my application.

<Border BorderBrush="Black" BorderThickness="2"> <Grid Height="166" HorizontalAlignment="Left" Margin="12,12,0,0" Name="grid1" VerticalAlignment="Top" Width="479" Background="#FFF2F2F2" /> </Border> ... and so on ... What do you mean by "whole thing"? I suspect you have something else inside your grid - you should perhaps post what that is. My suspicion is that you have some kind of datagrid control as well as your grid container (which is what you've put in your sample and would presumably contain the "whole thing") and that's where the confusion arises. Dan Puzey May 4, 2010 at 22:56

If you just want an outer border, the easiest way is to put it in a Border control:

<Border BorderBrush="Black" BorderThickness="2">
       <!-- Grid contents here -->
    </Grid>
</Border>

The reason you're seeing the border completely fill your control is that, by default, it's HorizontalAlignment and VerticalAlignment are set to Stretch. Try the following:

<Border HorizontalAlignment="Left" VerticalAlignment="Top" BorderBrush="Black" BorderThickness="2"> <Grid Height="166" HorizontalAlignment="Left" Margin="12,12,0,0" Name="grid1" VerticalAlignment="Top" Width="479" Background="#FFF2F2F2" /> </Border> </Grid>

This should get you what you're after (though you may want to put a margin on all 4 sides, not just 2...)

@ReedCopsey Reed, I know your solution works, what I don't understand is why the Border element is inside the Grid element - isn't this counter intuitive? Thank you. – Sabuncu Apr 12, 2013 at 20:29 @Sabuncu You'll notice that my original didn't have that - I was making the OP's edit "work" – Reed Copsey Apr 12, 2013 at 22:27 This seems to place a boarder around the inside of my main window and not around the outside of the grid that is encapsulated within it. Any ideas why? – Brady Nov 11, 2015 at 15:17 oh... okey :D thought there were a variable i overlooked or something fancy WPF (im new at it :D) – Jason94 May 4, 2010 at 22:45 You cannot create a Template for Grid and Border because they have no Template property as they are not derived from Control, but from Panel and Decorator. Reed Copsey has the (pretty simple) solution. – gehho May 5, 2010 at 6:37

This is a later answer that works for me, if it may be of use to anyone in the future. I wanted a simple border around all four sides of the grid and I achieved it like so...

<DataGrid x:Name="dgDisplay" Margin="5" BorderBrush="#1266a7" BorderThickness="1"...
<Grid x:Name="outerGrid">
    <Grid x:Name="innerGrid">
        <Border BorderBrush="#FF179AC8" BorderThickness="2" />
        <other stuff></other stuff>
        <other stuff></other stuff>
    </Grid>
</Grid>

This code Wrap a border inside the "innerGrid"

Hi @ElvinMammadov. Can you describe more. Are you getting any errors? This code works fine to me. – PJ3 Jul 4, 2016 at 4:15 Need to add Grid.ColumnSpan="the columns you want to cover" Grid.RowSpan= "The rows you want to cover" in Border tag. Otherwise it only covers the first cell. – user3707094 Jun 27, 2018 at 14:22

If someone is interested in the similar problem, but is not working with XAML, here's my solution:

var B1 = new Border();
B1.BorderBrush = Brushes.Black;
B1.BorderThickness = new Thickness(0, 1, 0, 0); // You can specify here which borders do you want
YourPanel.Children.Add(B1);
public class Sheet : Grid
    public static readonly DependencyProperty BorderBrushProperty = DependencyProperty.Register(nameof(BorderBrush), typeof(Brush), typeof(Sheet), new FrameworkPropertyMetadata(Brushes.Transparent, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, OnBorderBrushChanged));
    public static readonly DependencyProperty BorderThicknessProperty = DependencyProperty.Register(nameof(BorderThickness), typeof(double), typeof(Sheet), new FrameworkPropertyMetadata(1D, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, OnBorderThicknessChanged, CoerceBorderThickness));
    public static readonly DependencyProperty CellSpacingProperty = DependencyProperty.Register(nameof(CellSpacing), typeof(double), typeof(Sheet), new FrameworkPropertyMetadata(0D, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, OnCellSpacingChanged, CoerceCellSpacing));
    public Brush BorderBrush
        get => this.GetValue(BorderBrushProperty) as Brush;
        set => this.SetValue(BorderBrushProperty, value);
    public double BorderThickness
        get => (double)this.GetValue(BorderThicknessProperty);
        set => this.SetValue(BorderThicknessProperty, value);
    public double CellSpacing
        get => (double)this.GetValue(CellSpacingProperty);
        set => this.SetValue(CellSpacingProperty, value);
    protected override Size ArrangeOverride(Size arrangeSize)
        Size size = base.ArrangeOverride(arrangeSize);
        double border = this.BorderThickness;
        double doubleBorder = border * 2D;
        double spacing = this.CellSpacing;
        double halfSpacing = spacing * 0.5D;
        if (border > 0D || spacing > 0D)
            foreach (UIElement child in this.InternalChildren)
                this.GetChildBounds(child, out double left, out double top, out double width, out double height);
                left += halfSpacing + border;
                top += halfSpacing + border;
                height -= spacing + doubleBorder;
                width -= spacing + doubleBorder;
                if (width < 0D)
                    width = 0D;
                if (height < 0D)
                    height = 0D;
                left -= left % 0.5D;
                top -= top % 0.5D;
                width -= width % 0.5D;
                height -= height % 0.5D;
                child.Arrange(new Rect(left, top, width, height));
            if (border > 0D && this.BorderBrush != null)
                this.InvalidateVisual();
        return size;
    protected override void OnRender(DrawingContext dc)
        base.OnRender(dc);
        if (this.BorderThickness > 0D && this.BorderBrush != null)
            if (this.CellSpacing == 0D)
                this.DrawCollapsedBorder(dc);
                this.DrawSeperatedBorder(dc);
    private void DrawSeperatedBorder(DrawingContext dc)
        double spacing = this.CellSpacing;
        double halfSpacing = spacing * 0.5D;
        #region draw border
        Pen pen = new Pen(this.BorderBrush, this.BorderThickness);
        UIElementCollection children = this.InternalChildren;
        foreach (UIElement child in children)
            this.GetChildBounds(child, out double left, out double top, out double width, out double height);
            left += halfSpacing;
            top += halfSpacing;
            width -= spacing;
            height -= spacing;
            dc.DrawRectangle(null, pen, new Rect(left, top, width, height));
        #endregion
    private void DrawCollapsedBorder(DrawingContext dc)
        RowDefinitionCollection rows = this.RowDefinitions;
        ColumnDefinitionCollection columns = this.ColumnDefinitions;
        int rowCount = rows.Count;
        int columnCount = columns.Count;
        const byte BORDER_LEFT = 0x08;
        const byte BORDER_TOP = 0x04;
        const byte BORDER_RIGHT = 0x02;
        const byte BORDER_BOTTOM = 0x01;
        byte[,] borderState = new byte[rowCount, columnCount];
        int column = columnCount - 1;
        int columnSpan;
        int row = rowCount - 1;
        int rowSpan;
        #region generate main border data
        for (int i = 0; i < rowCount; i++)
            borderState[i, 0] = BORDER_LEFT;
            borderState[i, column] = BORDER_RIGHT;
        for (int i = 0; i < columnCount; i++)
            borderState[0, i] |= BORDER_TOP;
            borderState[row, i] |= BORDER_BOTTOM;
        #endregion
        #region generate child border data
        UIElementCollection children = this.InternalChildren;
        foreach (UIElement child in children)
            this.GetChildLayout(child, out row, out rowSpan, out column, out columnSpan);
            for (int i = 0; i < rowSpan; i++)
                borderState[row + i, column] |= BORDER_LEFT;
                borderState[row + i, column + columnSpan - 1] |= BORDER_RIGHT;
            for (int i = 0; i < columnSpan; i++)
                borderState[row, column + i] |= BORDER_TOP;
                borderState[row + rowSpan - 1, column + i] |= BORDER_BOTTOM;
        #endregion
        #region draw border
        Pen pen = new Pen(this.BorderBrush, this.BorderThickness);
        double left;
        double top;
        double width, height;
        for (int r = 0; r < rowCount; r++)
            RowDefinition v = rows[r];
            top = v.Offset;
            height = v.ActualHeight;
            for (int c = 0; c < columnCount; c++)
                byte state = borderState[r, c];
                ColumnDefinition h = columns[c];
                left = h.Offset;
                width = h.ActualWidth;
                if ((state & BORDER_LEFT) == BORDER_LEFT)
                    dc.DrawLine(pen, new Point(left, top), new Point(left, top + height));
                if ((state & BORDER_TOP) == BORDER_TOP)
                    dc.DrawLine(pen, new Point(left, top), new Point(left + width, top));
                if ((state & BORDER_RIGHT) == BORDER_RIGHT && (c + 1 >= columnCount || (borderState[r, c + 1] & BORDER_LEFT) == 0))
                    dc.DrawLine(pen, new Point(left + width, top), new Point(left + width, top + height));
                if ((state & BORDER_BOTTOM) == BORDER_BOTTOM && (r + 1 >= rowCount || (borderState[r + 1, c] & BORDER_TOP) == 0))
                    dc.DrawLine(pen, new Point(left, top + height), new Point(left + width, top + height));
        #endregion
    private void GetChildBounds(UIElement child, out double left, out double top, out double width, out double height)
        ColumnDefinitionCollection columns = this.ColumnDefinitions;
        RowDefinitionCollection rows = this.RowDefinitions;
        int rowCount = rows.Count;
        int row = (int)child.GetValue(Grid.RowProperty);
        if (row >= rowCount)
            row = rowCount - 1;
        int rowSpan = (int)child.GetValue(Grid.RowSpanProperty);
        if (row + rowSpan > rowCount)
            rowSpan = rowCount - row;
        int columnCount = columns.Count;
        int column = (int)child.GetValue(Grid.ColumnProperty);
        if (column >= columnCount)
            column = columnCount - 1;
        int columnSpan = (int)child.GetValue(Grid.ColumnSpanProperty);
        if (column + columnSpan > columnCount)
            columnSpan = columnCount - column;
        left = columns[column].Offset;
        top = rows[row].Offset;
        ColumnDefinition right = columns[column + columnSpan - 1];
        width = right.Offset + right.ActualWidth - left;
        RowDefinition bottom = rows[row + rowSpan - 1];
        height = bottom.Offset + bottom.ActualHeight - top;
        if (width < 0D)
            width = 0D;
        if (height < 0D)
            height = 0D;
    private void GetChildLayout(UIElement child, out int row, out int rowSpan, out int column, out int columnSpan)
        int rowCount = this.RowDefinitions.Count;
        row = (int)child.GetValue(Grid.RowProperty);
        if (row >= rowCount)
            row = rowCount - 1;
        rowSpan = (int)child.GetValue(Grid.RowSpanProperty);
        if (row + rowSpan > rowCount)
            rowSpan = rowCount - row;
        int columnCount = this.ColumnDefinitions.Count;
        column = (int)child.GetValue(Grid.ColumnProperty);
        if (column >= columnCount)
            column = columnCount - 1;
        columnSpan = (int)child.GetValue(Grid.ColumnSpanProperty);
        if (column + columnSpan > columnCount)
            columnSpan = columnCount - column;
    private static void OnBorderBrushChanged(DependencyObject d, DependencyPropertyChangedEventArgs args)
        if (d is UIElement element)
            element.InvalidateVisual();
    private static void OnBorderThicknessChanged(DependencyObject d, DependencyPropertyChangedEventArgs args)
        if (d is UIElement element)
            element.InvalidateArrange();
    private static void OnCellSpacingChanged(DependencyObject d, DependencyPropertyChangedEventArgs args)
        if (d is UIElement element)
            element.InvalidateArrange();
    private static object CoerceBorderThickness(DependencyObject d, object baseValue)
        if (baseValue is double value)
            return value < 0D || double.IsNaN(value) || double.IsInfinity(value) ? 0D : value;
        return 0D;
    private static object CoerceCellSpacing(DependencyObject d, object baseValue)
        if (baseValue is double value)
            return value < 0D || double.IsNaN(value) || double.IsInfinity(value) ? 0D : value;
        return 0D;

a demo:

If attempting to wrap a Grid that has been seperated into Columns and Rows, you can use the span option like so.

<Grid Grid.ColumnSpan="4"  Grid.Row ="1" Grid.RowSpan="3" ShowGridLines="True" >
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"></ColumnDefinition>
        <ColumnDefinition Width="*"></ColumnDefinition>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="*"></RowDefinition>
        <RowDefinition Height="*"></RowDefinition>
        <RowDefinition Height="*"></RowDefinition>
        <RowDefinition Height="*"></RowDefinition>
    </Grid.RowDefinitions>
    <Border Margin="10" BorderBrush="Gray" BorderThickness="2" Grid.ColumnSpan="2" Grid.RowSpan="4"/>
</Grid>

Gives you this:

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.