Welcome to Pete Brown's 10rem.net

First time here? If you are a developer or are interested in Microsoft tools and technology, please consider subscribing to the latest posts.

You may also be interested in my blog archives, the articles section, or some of my lab projects such as the C64 emulator written in Silverlight.

(hide this)

Silverlight Tip : Nest Another Grid Inside LayoutRoot for Flexibility

Pete Brown - 30 March 2009

This is something I’ve been doing since we first got LayoutRoot, and it has saved me aggravation a number of times. This works in Silverlight 2 and Silverlight 3 (the drop shadow effect in the example below only works in Silverlight 2).

Simply put: I never set column definitions, margins or anything else related to layout directly on layout root. Instead, I nest another grid inside it and work with that.

I was asked if I consider this a preference or a best practice. Given the iterative approach we usually take to designing and developing our apps, I would say this definitely falls under the best practice category.

Here’s an example of the nested grid approach. Note that I didn’t set margins, rows or columns on LayoutRoot.

<UserControl x:Class="PeteBrown.ScratchProject.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    
    <Grid x:Name="LayoutRoot">
        
        <Grid Margin="5">
            <Grid.RowDefinitions>
                <RowDefinition Height="100" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="*" />
            </Grid.RowDefinitions>
            
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="350" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            
            <!-- Content goes here -->

        </Grid>

    </Grid>
    
</UserControl>

This way, I can easily add a border or other elements later without having to move everything around. Consider the case where you put together this app, and decide you want to put a border around the content. If you defined all the columns and rows directly on layout root, you’d either need to move them all to a second grid now, or make the border the LayoutRoot. But if you made the border LayoutRoot and had code expecting LayoutRoot to be a panel, then you’d have to fix that as well.

Say you wanted to add an interesting background rectangle to your layout. If you set the rows/columns/margins on layout root, you’d have to live within those (with an ugly RowSpan and ColumnSpan setting and negative margins) or again, move the grid down to another level.

Here’s an example of what I’m talking about. As I iterated through this, adding the columns, and then adding the background rectangle, I’d have had to do a lot of shifting if I attached everything directly to LayoutRoot.

image

<UserControl x:Class="PeteBrown.ScratchProject.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    
    <Grid x:Name="LayoutRoot">

        <Rectangle x:Name="BackgroundRectangle"
                   RadiusX="5"
                   RadiusY="5"
                   Margin="10"
                   Fill="#FF323242">
            <Rectangle.Effect>
                <DropShadowEffect BlurRadius="20"
                                  Direction="0"
                                  Opacity="1"
                                  ShadowDepth="0" />
            </Rectangle.Effect>

        </Rectangle>
        
        <Grid Margin="20">
            <Grid.RowDefinitions>
                <RowDefinition Height="100" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="*" />
            </Grid.RowDefinitions>
            
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="350" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            
            <!-- Content goes here -->
            <TextBlock Text="Here lies the content. May she rest in peace."
                       FontSize="14"
                       Foreground="White"
                       TextWrapping="Wrap"/>
        </Grid>

    </Grid>
    
</UserControl>
Note above that the rectangle sits within LayoutRoot so I don’t have to fiddle with row and column spans, and don’t have to set negative margins. The content sits within the inside grid.

This also gives you the freedom to use something other than a grid (a canvas or stackpanel), while still keeping the LayoutRoot itself as a grid. This may be important to how your application is structured.

   
posted by Pete Brown on Monday, March 30, 2009
filed under:    

7 comments for “Silverlight Tip : Nest Another Grid Inside LayoutRoot for Flexibility”

  1. Andy says:
    Nested rules! My code features many 'deep grids', as grids are the easiest way of justifing UIElements and Controls - Left, right, center, top and bottom. This way <grid> is rather like the classic <table> tag. Personally, I've avoided stackpanels!
  2. Paulosays:
    Hey there! I was reading your blog and found this post. Very useful. I'm using Silverlight 2 and I can't use the effects on the rectangle. Is there any reason for this? Am I missing something?

    Cheers
  3. thusharasays:
    Hi ,

    i am new to SL developments, i just want to know how to desing UI layout similar to what we did with HTML TABLES .
    my Layout as follows , i need to add grid with in the row , refer ****

    <Grid x:Name="LayoutRoot" >


    <Grid.RowDefinitions>
    <RowDefinition Height="10"/> <!-- padding -->
    <RowDefinition Height="50"/> <!-- Menu -->
    <RowDefinition Height="10"/> <!-- Padding -->
    <RowDefinition Height="400"><!-- General Info -->

    *** i want to partition this area with a new grid. with 3 columns and 10 rows

    </RowDefinition>
    <RowDefinition Height="10"/> <!-- Padding -->
    <RowDefinition Height="200"/> <!-- Tab Control -->
    <RowDefinition Height="10"/> <!-- Padding -->
    <RowDefinition Height="200"/> <!-- Remarks -->

    </Grid.RowDefinitions>

    <Grid.ColumnDefinitions>
    <ColumnDefinition Width="10"/> <!-- padding -->
    <ColumnDefinition Width="380"/><!-- Left content -->
    <ColumnDefinition Width="20"/><!-- padding -->
    <ColumnDefinition Width="380"/><!-- Right content -->
    <ColumnDefinition Width="10"/><!-- padding -->

    </Grid.ColumnDefinitions>
    </Grid></Grid>

    if any one know how to add nested grid in SL , please help me ..
    Thanks
  4. Petesays:
    @thushara

    be sure to spend some time on the forums at http://silverlight.net as well.

    I'll help with this specific problem, but you should probably rethink your approach. Margins and padding are built into controls as properties, so you don't need to create empty grid cells (typically) to do it.

    The trick is to just include the second grid as content, and set its Grid.Row and Grid.Column properties.

    <!-- Air xaml. use with caution -->
    <Grid>
    <Grid.RowDefinitions>
    <RowDefinition Height="100" /> <!-- row 0 -->
    <RowDefinition Height="120" /> <!-- row 1 -->
    <RowDefinition Height="*" /> <!-- row 2 -->
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
    <ColumnDefinition Width="50" /> <!-- column 0 -->
    <ColumnDefinition Width="50" /> <!-- column 1 -->
    </Grid.ColumnDefinitions>

    <TextBlock Grid.Row="0" Grid.Column="0" Text="Blah blah blah" />

    <Grid Grid.Row="1" Grid.Column="1">
    ... <!-- column and row defs, and content for this grid -->
    </Grid>

    </Grid>

Comment on this Post

Remember me