Deborah's Developer MindScape






         Tips and Techniques for Web and .NET developers.

November 17, 2009

Silverlight: No More Boxy UIs

Filed under: C#,Silverlight,VB.NET @ 5:11 pm

As WinForms and WebForms developers, we are used to building user interfaces (UIs) that look like this:

image

Notice the rectangular header area and the rectangular link area and the rectangular data entry area.

With Silverlight it is (relatively) easy to give the UI less of a boxy look:

image

So the above UI may not be amazing, but it should give you some ideas about the kinds of things you can do to make your Silverlight applications look a little less square.

To make it easier to try this yourself, all of the source code for this User Control is included at the bottom of this post.

NOTE: This example uses a medium gray and white for the two background colors and a shade of red for the labels. You can change this to any color scheme you would like for your application by adjusting the color resources defined at the top of the code.

Designing the Layout

Even though the goal is to have a non-boxy style user interface, this effect is achieved using a set of grids. The grids are laid out as follows:

image

The user control is comprised of one primary grid, called LayoutRoot in the sample code. It has two rows as shown with two red rectangles above. The top row contains the header information and the bottom row contains the content information.

The top row of the LayoutRoot grid contains another grid, called HeaderGrid in the sample code. It contains two columns as shown with two blue rectangles above. The first column contains the logo and the second column contains the application title.

The background of the HeaderGrid is set to the background color defined for the application. In this example, the color is a medium gray.

NOTE: You cannot easily use a StackPanel here instead of a Grid because the background color needs to stretch across the entire width of the control. With a StackPanel, the background only covers the controls within the StackPanel. If you use a StackPanel, ensure your controls are resized to the full width of the user control.

The bottom row of the LayoutRoot grid contains another grid, called ContentGrid in the sample code. It contains three columns as shown with the two green rectangles above along with the red vertical line between them.

The background of the ContentGrid is where the magic takes place. It contains the radial gradient which displays the arc.

[For an overview of Silverlight gradients, see this prior post.]

NOTE: If you define a background for any of the controls within the ContentGrid, the ContentGrid background will not appear properly.

Defining the Gradient

The gradient used to achieve the arc depicted in the design is as follows:

  <Grid.Background>
      <RadialGradientBrush>
          <RadialGradientBrush.RelativeTransform >
              <TransformGroup>
                  <ScaleTransform 
                      CenterX="0.5" 
                      ScaleY="2" ScaleX="2.5"/>
                  <SkewTransform/>
                  <RotateTransform/>
                  <TranslateTransform/>
              </TransformGroup>
          </RadialGradientBrush.RelativeTransform>
          <GradientStop Color="White" Offset="0.95"/>
          <GradientStop 
                 Color="{StaticResource BackgroundColor}" 
                 Offset=".98"/>
      </RadialGradientBrush>
  </Grid.Background>

To better understand this XAML, let’s take it step by step. The following sets of screen shots were taken using Expression Blend 3.

Add a simple radial gradient to the ContentGrid background with code like this:

<RadialGradientBrush>
    <GradientStop Color="White" Offset="0"/>
    <GradientStop Color="{StaticResource BackgroundColor}"
                  Offset="1"/>
</RadialGradientBrush>

The Silverlight control appears like this:

image

Notice that the center point of the bottom grid is white and radiates out to a medium gray. While this may also be an interesting effect, it is not what is needed for this example.

For this example, the majority of the background should be white. So the first change is to the gradient Offset values:

<RadialGradientBrush>
    <GradientStop Color="White" Offset=".95"/>
    <GradientStop Color="{StaticResource BackgroundColor}"
                  Offset=".98"/>
</RadialGradientBrush>

The result is as follows:

image

By setting the white Offset to .95, the white center point does not begin the gradient effect until 95% of the way through the gradient radius. This leaves the majority of the background white.

Setting the Offset values closer to each other, the actual gradient effect is very small as shown in the red circled area above.

For a wider gradient with more space between the white and the gray, adjust the Offset values until you get the desired result. For example, with Offsets of .70 and .98, the gradient between the white and the gray is much wider:

image

Once you get the desired gradient effect, you can resize the ellipse. In this example, only the top of the gradient ellipse is desired. To resize the gradient to get the desired effect, use the gradient RelativeTransform property:

<RadialGradientBrush.RelativeTransform >
    <TransformGroup>
        <ScaleTransform CenterX="0.5" ScaleY="2" ScaleX="2.5"/>
        <SkewTransform/>
        <RotateTransform/>
        <TranslateTransform/>
    </TransformGroup>
</RadialGradientBrush.RelativeTransform>

The ScaleY defines the height of the ellipse. By default, the ellipse is one unit tall. If you want only the top half of the ellipse, you can set the ScaleY=2. This doubles the size so you only get the top half of the ellipse. The result is as follows:

image

Adjust the ScaleX property to change the width of the ellipse and flatten the arc. Setting ScaleX to 2.5 results in the following:

image

That flattened the arc, but now the ellipse is no longer centered. To fix that, adjust the CenterX property. Setting CenterX to .5 results in desired layout:

image

Now that it is centered, adjust the ScaleX and ScaleY values until you get the desired arc. Try out the other transformation features and see what looks you can achieve.

Enjoy!

Full Source Code

<UserControl x:Class="SLVB.MainPage"
    xmlns="
http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:dataInput="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.Input"
    xmlns:x="
http://schemas.microsoft.com/winfx/2006/xaml"
    mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">

    <UserControl.Resources>
        <Color x:Key="BackgroundColor">#959595</Color>
        <Color x:Key="ForegroundColor">#E5E5E5</Color>
        <Color x:Key="LabelColor">#95002C</Color>
        <SolidColorBrush x:Key="BackgroundBrush"
           Color="{StaticResource BackgroundColor}"/>
        <SolidColorBrush x:Key="ForegroundBrush" 
           Color="{StaticResource ForegroundColor}"/>
        <SolidColorBrush x:Key="LabelBrush"
           Color="{StaticResource LabelColor}"/>

        <Style x:Key="HeaderStyle" TargetType="dataInput:Label">
            <Setter Property="FontFamily" Value="Arial" />
            <Setter Property="FontSize" Value="20" />
            <Setter Property="FontWeight" Value="Bold" />
            <Setter Property="Foreground"
                    Value="{StaticResource LabelBrush}" />
        </Style>
        <Style x:Key="LabelStyle" TargetType="dataInput:Label">
            <Setter Property="Foreground"
                    Value="{StaticResource LabelBrush}" />
        </Style>
        <Style x:Key="LinkStyle" TargetType="HyperlinkButton">
            <Setter Property="Foreground"
                    Value="{StaticResource LabelBrush}"/>
            <Setter Property="FontSize" Value="12"/>
            <Setter Property="Padding" Value="8,4,8,4"/>
        </Style>
    </UserControl.Resources>

    <Grid x:Name="LayoutRoot">
        <Grid.RowDefinitions>
            <!– Header –>
            <RowDefinition Height="auto"/>
            <!– Content –>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <!– Header –>
        <Grid x:Name="HeaderGrid" Grid.Row="0"
              Background="{StaticResource BackgroundBrush}">
            <Grid.ColumnDefinitions>
                <!– Icon –>
                <ColumnDefinition Width="auto"></ColumnDefinition>
                <!– Text –>
                <ColumnDefinition Width="*"></ColumnDefinition>
            </Grid.ColumnDefinitions>

            <Image Source="Images/Logo.png"
                   Grid.Row="0" Grid.Column="0"
                   Margin="5"
                   HorizontalAlignment="Left"
                   Width="100"/>
            <TextBlock x:Name="ApplicationTextTextBlock"
                       Grid.Row="0" Grid.Column="1"
                       Foreground="{StaticResource ForegroundBrush}"
                       FontSize="32"
                       TextAlignment="Center"
                       Margin="0,0,10,5"
                       VerticalAlignment="Center"
                       Text="Customer Management">
            </TextBlock>
        </Grid>

        <!– Content –>
        <Grid x:Name="ContentGrid" Grid.Row="1">
            <Grid.Background>
                <RadialGradientBrush>
                    <RadialGradientBrush.RelativeTransform >
                        <TransformGroup>
                            <ScaleTransform CenterX="0.5"
                                     ScaleY="2" ScaleX="2.5"/>
                            <SkewTransform/>
                            <RotateTransform/>
                            <TranslateTransform/>
                        </TransformGroup>
                    </RadialGradientBrush.RelativeTransform>
                    <GradientStop Color="White" Offset="0.95"/>
                    <GradientStop 
                           Color="{StaticResource BackgroundColor}"
                                      Offset=".98"/>
                </RadialGradientBrush>
            </Grid.Background>

            <Grid.ColumnDefinitions>
                <!– Links –>
                <ColumnDefinition Width="auto"></ColumnDefinition>
                <!– Divider –>
                <ColumnDefinition Width="auto"></ColumnDefinition>
                <!– Content –>
                <ColumnDefinition Width="*"></ColumnDefinition>
            </Grid.ColumnDefinitions>

            <StackPanel x:Name="LinksStackPanel" Grid.Column="0">
                <Rectangle x:Name="Divider0"
                   Height="40"/>
                <HyperlinkButton x:Name="CustomerLink"
                   Content="Customer Info"
                   Style="{StaticResource LinkStyle}"/>
                <HyperlinkButton x:Name="AddressLink"
                   Content="Addresses" 
                   Style="{StaticResource LinkStyle}"/>
                <HyperlinkButton x:Name="EmailAddressLink"
                   Content="Email Addresses"
                   Style="{StaticResource LinkStyle}"/>
            </StackPanel>

            <Line Grid.Column="1"  Fill="White" Stretch="Fill"
                 Stroke="{StaticResource LabelBrush}"
                 StrokeThickness="2.5"
                 X1="0" Y1="0" X2="0" Y2="1"/>
            <Canvas Grid.Column="2">
                <dataInput:Label Canvas.Left="17" Canvas.Top="19"
                     Content="Address"
                     Style="{StaticResource HeaderStyle}" />
                <Path Fill="White" Stretch="Fill" 
                     Stroke="{StaticResource LabelBrush}"
                     Height="2.5" Width="370"
                     Canvas.Left="17" Canvas.Top="46"
                     Data="M17,46 L611.5,46"/>

                <dataInput:Label Canvas.Left="33" Canvas.Top="57"
                     Content="Street:"
                     Style="{StaticResource LabelStyle}"/>
                <TextBox x:Name="Street1TextBox"
                     Canvas.Left="102" Canvas.Top="53" Text="" 
                     TextWrapping="NoWrap" Width="250"/>
                <TextBox x:Name="Street2TextBox"
                     Canvas.Left="102" Canvas.Top="81" Text="" 
                     TextWrapping="NoWrap" Width="250"/>

                <dataInput:Label Canvas.Left="34" Canvas.Top="125"
                     Content="City, State:" 
                     Style="{StaticResource LabelStyle}"/>
                <TextBox x:Name="CityTextBox"
                     Canvas.Left="102" Canvas.Top="121"
                     Text="" TextWrapping="NoWrap" Width="200"/>
                <TextBox x:Name="StateTextBox"
                     Canvas.Left="306" Canvas.Top="121"
                     Text="" TextWrapping="NoWrap" Width="45"/>

                <dataInput:Label Canvas.Left="34" Canvas.Top="158"
                     Content="Zip code:" 
                     Style="{StaticResource LabelStyle}"/>
                <dataInput:Label Canvas.Left="34" Canvas.Top="192"
                     Content="Country:" 
                     Style="{StaticResource LabelStyle}"/>
                <TextBox x:Name="CountryTextBox" 
                     Canvas.Left="102" Canvas.Top="186"
                     Text="" TextWrapping="NoWrap" Width="250"/>
                <TextBox x:Name="ZipTextBox"
                     Canvas.Left="102" Canvas.Top="153"
                     Text="" TextWrapping="NoWrap" Width="250"/>
                <Button x:Name="OKButton" Width="75"
                     Canvas.Left="238" Canvas.Top="230"
                     Content="OK" />
                <Button x:Name="CancelButton" Width="75" 
                     Canvas.Left="317" Canvas.Top="230"
                     Content="Cancel" />
            </Canvas>
        </Grid> 
    </Grid>
</UserControl>

4 Comments

  1.   Mark Wisecarver — November 17, 2009 @ 6:01 pm    Reply

    Once again…Awesome!
    Thanks a bunch ;-)
    http://twitter.com/msftwise

  2.   Greg — November 19, 2009 @ 3:13 pm    Reply

    Please keep in mind that persons 40 years and older will have difficulty with:
    – Gradients
    – Too many colors
    – Similar colors on top of each other (light brown text on brown background).
    – Too many rounded corners
    – Too many lines
    – Fixed font size
    – Color scheme is low contrast

  3.   DeborahK — November 19, 2009 @ 11:12 pm    Reply

    Thanks for your suggestions, Greg.

    As someone on the “better” side of 40, I find that gradients are softer on the eyes. But I agree on the other points. The easy font size adjustment is one of my favorite things in Win7.

    Thanks again.

  4.   Greg — November 23, 2009 @ 10:42 am    Reply

    Here is a simple test I use when reviewing our developed applications/web sites.

    – Take a screen shapshot of the application
    – Open in Gimp/photoshop
    – Convert to grayscale
    – Find edges in the application
    – Thicken the edges by 1 or 2 pixels
    – Review that with the development team to show the noise in the GUI

    Open other helpful GUI tip for those over 40 and more so for those 60 or older is to minimize or remove the animated icons/click hit bitmaps. This is especially distracting and counter productive for older users.

RSS feed for comments on this post. TrackBack URI

Leave a comment

© 2014 Deborah's Developer MindScape   Provided by WPMU DEV -The WordPress Experts   Hosted by Microsoft MVPs