Assigning border to every Grid row

51,109

Solution 1

You could pull that border out into a reusable resource, but I suspect what you're really trying to do is create a GridView.

Solution 2

Or you could use this grid I just made. It will automatically add a border to every cell in the grid. This is the result:

enter image description here

C#:

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

namespace GridWithBorder
{
   public class BorderGrid : Grid
   {
       protected override void OnRender(DrawingContext dc)
       {
           double leftOffset = 0;
           double topOffset = 0;
           Pen pen = new Pen(Brushes.Black, 3);
           pen.Freeze();

           foreach (RowDefinition row in this.RowDefinitions)
           {
               dc.DrawLine(pen, new Point(0, topOffset), new Point(this.ActualWidth, topOffset));
               topOffset += row.ActualHeight;
           }
            // draw last line at the bottom
        dc.DrawLine(pen, new Point(0, topOffset), new Point(this.ActualWidth, topOffset));

           //foreach (ColumnDefinition column in this.ColumnDefinitions)
           //{
           //   dc.DrawLine(pen, new Point(leftOffset, 0), new Point(leftOffset, this.ActualHeight));
           //   leftOffset += column.ActualWidth;
           //}
           // draw last line on the right
           //dc.DrawLine(pen, new Point(leftOffset, 0), new Point(leftOffset, this.ActualHeight));

           base.OnRender(dc);
       }
   }
}

XAML:

<Window x:Class="GridWithBorder.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:GridWithBorder"
        Title="MainWindow" Height="350" Width="525">
    <local:BorderGrid>
        <local:BorderGrid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
            <RowDefinition />
        </local:BorderGrid.RowDefinitions>
        <local:BorderGrid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
            <ColumnDefinition />
            <ColumnDefinition />
        </local:BorderGrid.ColumnDefinitions>
        <Rectangle Grid.Row="0" Grid.Column="0" Fill="Red" Margin="5" />
        <Rectangle Grid.Row="0" Grid.Column="1" Fill="Blue" Margin="5" />
        <Rectangle Grid.Row="0" Grid.Column="2" Fill="Orange" Margin="5" />
        <Rectangle Grid.Row="0" Grid.Column="3" Fill="Red" Margin="5" />
        <Rectangle Grid.Row="1" Grid.Column="0" Fill="Yellow" Margin="5" />
        <Rectangle Grid.Row="1" Grid.Column="1" Fill="Green" Margin="5" />
        <Rectangle Grid.Row="1" Grid.Column="2" Fill="Purple" Margin="5" />
        <Rectangle Grid.Row="1" Grid.Column="3" Fill="Green" Margin="5" />
        <Rectangle Grid.Row="2" Grid.Column="0" Fill="Orange" Margin="5" />
        <Rectangle Grid.Row="2" Grid.Column="1" Fill="Red" Margin="5" />
        <Rectangle Grid.Row="2" Grid.Column="2" Fill="Blue" Margin="5" />
        <Rectangle Grid.Row="2" Grid.Column="3" Fill="Red" Margin="5" />
    </local:BorderGrid>
</Window>

Solution 3

You can just set the Background property on your Grid. If there is commonality between the border which you are applying to the different rows, you can create a default style (and if desired, limit the scope of this style to the Grid itself):

XAML

<Grid>
    <Grid.Resources>
        <Style TargetType="{x:Type Border}">
            <!-- All rows -->
            <Setter Property="BorderBrush" Value="Black" />
            <Setter Property="BorderThickness" Value="2" />
            <Setter Property="CornerRadius" Value="5" />
        </Style>
    </Grid.Resources>

    <Grid.RowDefinitions>
        <RowDefinition />
        <RowDefinition />
        <RowDefinition />
    </Grid.RowDefinitions>

    <Border Grid.Row="0">
        <TextBlock Text="This row has a black border (default)." />
    </Border>

    <Border BorderBrush="Red" Grid.Row="1">
        <TextBlock Text="This row has a red border." />
    </Border>

    <Border BorderBrush="Green" BorderThickness="4" Grid.Row="2">
        <TextBlock Text="This has a thick green border." />
    </Border>

</Grid>

With a default Style, no additional property needs to be set on your row's Border to achieve a default look (row one above). If a certain row needs to tweak the look and feel, then just provide additional properties on the Border to override the ones set in the default Style (rows two and three above). If this technique is something you are applying across multiple views in your application, then you can extract this style into a separate ResourceDictionary and simply merge it where appropriate.

Hope this helps!

Share:
51,109
dotancohen
Author by

dotancohen

I currently develop and support the backends of a few LAMP-stack based web applications for BSS (Business Support Services) that my company specializes in. I have experience in software project management, business process development, and I ran a software development business for a short time (actually twice). I have been using PHP since 1998 or '99, and I'm reasonably competent in the associated client-side technologies. I find myself using Python often, mostly for my own personal projects, I'm quite poetic in VIM, and of course Git is a cornerstone of my development. Lately I have been experimenting with machine learning, mostly with scikit-learn.

Updated on August 26, 2020

Comments

  • dotancohen
    dotancohen almost 4 years

    Currently I am setting the background on each Grid row individually:

    <Grid>
        <Grid.RowDefinitions><RowDefinition /><RowDefinition /></Grid.RowDefinitions>
        <Grid.ColumnDefinitions><ColumnDefinition /><ColumnDefinition /><ColumnDefinition /><ColumnDefinition /><ColumnDefinition /><ColumnDefinition /></Grid.ColumnDefinitions>
    
        <Border Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="6" Height="24" BorderBrush="#FF252A30" CornerRadius="10" BorderThickness="1">
            <Border.Background>
                <LinearGradientBrush EndPoint="1.036,0.367" StartPoint="-0.194,0.362">
                    <GradientStop Color="#AAE098" Offset="0.1"/>
                    <GradientStop Color="#D5E9D4" Offset="0.9"/>
                </LinearGradientBrush>
            </Border.Background>
        </Border>
    
        <Border Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="6" Height="24" BorderBrush="#FF252A30" CornerRadius="10" BorderThickness="1">
            <Border.Background>
                <LinearGradientBrush EndPoint="1.036,0.367" StartPoint="-0.194,0.362">
                    <GradientStop Color="#AAE098" Offset="0.1"/>
                    <GradientStop Color="#D5E9D4" Offset="0.9"/>
                </LinearGradientBrush>
            </Border.Background>
        </Border>
    </Grid>
    

    Surely there must be some way to set this Border once for all rows. How is that done?

    Thanks!

  • dotancohen
    dotancohen over 12 years
    Hello F Ruffell! The background is not solid across the entire Grid, rather, each row has it's own rounded corners at the beginning of the first cell and at the end of the last cell. Also, the example that you mention still requires the dev to update the Border element for each row individually if the requirement for the BorderThickness changes.
  • FunnyItWorkedLastTime
    FunnyItWorkedLastTime over 12 years
    By moving the commonly set properties into a default style that is scoped to the Grid, then the Border element does not properties to be set (other than color for example), and this approach does not repeat itself (e.g. BorderThickness is specified once only and hence needs to be updated only once). See edited response above :)
  • dotancohen
    dotancohen over 12 years
    Thanks, this is clever. I am having a hard time modifying it to put borders around each row, not each cell. Nice idea, though, until this point I was trying to do it only in XAML.
  • Carlo
    Carlo over 12 years
    @dotancohen ah ok, then just comment the part I just commented in the C# code, you'll get this result screencast.com/t/NwdxtGQNyq. Lmk if you need the first and last vertical lines (to have the border around the whole grid) I can do that too.
  • Carlo
    Carlo over 12 years
    @dotancohen example of border all around the grid and rows but not the columns here: screencast.com/t/d8GNqXRKGPf
  • dotancohen
    dotancohen over 12 years
    Thanks, Carlo, I am still playing with it. I need to figure out what properties are valid in the foreach, and I've gone through all the Intellisense suggestions but I cannot seem to find a read Background property. The issue is not only borders, it is also rounded corners and a solid background. Pen can't do that! This is how the code in the original post displays, I need to learn to create all those effects. Note that the rows are bound to an ObservableCollection so they will be updated on the fly.
  • Carlo
    Carlo over 12 years
    Ah ok, that can be done but it could get a little more complex (and fun!), I'll certainly look into it as soon as I get some time.
  • dotancohen
    dotancohen over 12 years
    I think that you are definitely right. What is the 'reusable resource' that into which I can put the border?
  • dotancohen
    dotancohen over 12 years
    Actually, I do agree that XAML is fun! I wouldn't say the same for some technologies but the whole non-C-based .NET stack (XAML and Linq for instance) really are entertaining to use and learn. Thank you for the help, it certainly helps to get me on the track of what to Google for.
  • dotancohen
    dotancohen over 12 years
    @F Ruffell: Thank you, but the styles still affect only individual cells, not entire rows. To demonstrate, if you add Grid.Column attributes to the Border elements, then it can be seen that each cell has rounded edges, not each row. My goal is to have each row a solid colour, but with rounded edges at the corners of the row. The code in the OP does this, but it needs to be defined (and updated) for each row individually. I would like to abstract that into a style that is reused for each row.