If you’re creating a Silverlight Out-Of-Browser application then it’s pretty easy to turn off the default window chrome. Simply change the Window Style setting on your Silverlight project to “No Border” (via the Properties dialog –> Out of Browser Settings dialog). However, if you do that you need to take care of resizing, closing and dragging of the window.

In this example, I’m going to assume you have a master page that contains a navigation frame into which your application pages are loaded. This master page can contain all the logic to control your application window.

My master page looks like,

<navigation:Page xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" 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:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation" xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"  x:Class="OutageNotices.ApplicationFrame"
           d:DesignWidth="640" d:DesignHeight="480"
           Title="Main Page" mc:Ignorable="d" SizeChanged="Page_SizeChanged">
 
    <Grid x:Name="LayoutRoot" MouseLeftButtonDown="Page_MouseLeftButtonDown">
        
        <Grid.Background>
            <ImageBrush ImageSource="/OutageNotices;component/Images/background.jpg" Opacity="0.03"/>
        </Grid.Background>
 
        <Grid.RowDefinitions>
            <RowDefinition Height="2"/>
            <RowDefinition Height="20"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="20"/>
            <RowDefinition Height="2"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="2"/>
            <ColumnDefinition Width="20"></ColumnDefinition>
            <ColumnDefinition Width="*"></ColumnDefinition>
            <ColumnDefinition Width="20"></ColumnDefinition>
            <ColumnDefinition Width="3"/>
        </Grid.ColumnDefinitions>
 
        <!-- Borders -->
        <Rectangle Tag="Top" Fill="{StaticResource BorderBrush}"  Grid.Column="1" Grid.ColumnSpan="3" Cursor="SizeNS" MouseLeftButtonDown="border_MouseLeftButtonDown"></Rectangle>
        <Rectangle Tag="Bottom" Fill="{StaticResource BorderBrush}" Grid.Column="1" Grid.ColumnSpan="3" Grid.Row="4" Cursor="SizeNS" MouseLeftButtonDown="border_MouseLeftButtonDown"></Rectangle>
        <Rectangle Tag="Left" Fill="{StaticResource BorderBrush}" Grid.Row="1" Grid.RowSpan="3" Cursor="SizeWE" MouseLeftButtonDown="border_MouseLeftButtonDown"></Rectangle>
        <Rectangle Tag="Right" Fill="{StaticResource BorderBrush}" Grid.Row="1" Grid.RowSpan="3" Grid.Column="4" Cursor="SizeWE" MouseLeftButtonDown="border_MouseLeftButtonDown"></Rectangle>
        <Rectangle Tag="TopLeft" Fill="{StaticResource BorderBrush}" Cursor="SizeNWSE" MouseLeftButtonDown="border_MouseLeftButtonDown"></Rectangle>
        <Rectangle Tag="TopRight" Fill="{StaticResource BorderBrush}" Grid.Column="4" Cursor="SizeNESW" MouseLeftButtonDown="border_MouseLeftButtonDown"></Rectangle>
        <Rectangle Tag="BottomLeft" Fill="{StaticResource BorderBrush}" Grid.Row="4" Cursor="SizeNESW" MouseLeftButtonDown="border_MouseLeftButtonDown"></Rectangle>
        <Rectangle Tag="BottomRight" Fill="{StaticResource BorderBrush}" Grid.Row="4" Grid.Column="4" Cursor="SizeNWSE" MouseLeftButtonDown="border_MouseLeftButtonDown"></Rectangle>
        <HyperlinkButton Tag="BottomRight" x:Name="resizeButton"  Width="10" Height="10" Grid.Row="3" Grid.Column="3" ClickMode="Hover" HorizontalAlignment="Right" VerticalAlignment="Bottom" MouseLeftButtonDown="border_MouseLeftButtonDown" Cursor="SizeNWSE" IsTabStop="False" >
            <HyperlinkButton.Background>
                <ImageBrush ImageSource="/OutageNotices;component/Images/resize.png"></ImageBrush>
            </HyperlinkButton.Background>
        </HyperlinkButton>
        
        <!-- header row -->
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Grid.Row="1" Grid.ColumnSpan="4">
            <HyperlinkButton NavigateUri="/Core/CheckingForUpdates.xaml" FontSize="8" VerticalAlignment="Center" Margin="0,0,0,0" IsTabStop="False">CHECK FOR UPDATES</HyperlinkButton>
            
            <TextBlock Foreground="{StaticResource XeroMidOrangeBrush}">|</TextBlock>
            
            <HyperlinkButton x:Name="aboutButton" FontSize="8" VerticalAlignment="Center" Margin="0,0,30,0" IsTabStop="False" Click="aboutButton_Click" >ABOUT</HyperlinkButton>
            
            <HyperlinkButton x:Name="minimizeButton" Width="12" Margin="5,0,0,0" Click="minimizeButton_Click" IsTabStop="False" Opacity="0.5" MouseEnter="HyperLinkButton_MouseEnter" MouseLeave="HyperLinkButton_MouseLeave">
                <HyperlinkButton.Background>
                    <ImageBrush ImageSource="/OutageNotices;component/Images/minimizeButton.png" Stretch="None"/>
                </HyperlinkButton.Background>
                <ToolTipService.ToolTip>
                    <ToolTip Margin="0,30,0,0" Content="Minimize"/>
                </ToolTipService.ToolTip>
            </HyperlinkButton>
            
            <HyperlinkButton x:Name="maximizeButton" Width="12" Margin="5,0,0,0" Click="maximizeButton_Click" IsTabStop="False" Opacity="0.5"  MouseEnter="HyperLinkButton_MouseEnter" MouseLeave="HyperLinkButton_MouseLeave">
                <HyperlinkButton.Background>
                    <ImageBrush ImageSource="/OutageNotices;component/Images/maximizeButton.png" Stretch="None"/>
                </HyperlinkButton.Background>
                <ToolTipService.ToolTip>
                    <ToolTip Margin="0,30,0,0" Content="Maximise"/>
                </ToolTipService.ToolTip>
            </HyperlinkButton>
            
            <HyperlinkButton x:Name="restoreButton" Width="12" Margin="5,0,0,0" Click="restoreButton_Click" Visibility="Collapsed" IsTabStop="False" Opacity="0.5" MouseEnter="HyperLinkButton_MouseEnter" MouseLeave="HyperLinkButton_MouseLeave">
                <HyperlinkButton.Background>
                    <ImageBrush ImageSource="/OutageNotices;component/Images/restoreButton.png" Stretch="None"/>
                </HyperlinkButton.Background>
                <ToolTipService.ToolTip>
                    <ToolTip Margin="0,30,0,0" Content="Restore"/>
                </ToolTipService.ToolTip>
            </HyperlinkButton>
            
            <HyperlinkButton x:Name="closeButton" Width="12" Margin="5,0,5,0" Click="closeButton_Click" IsTabStop="False" Opacity="0.5"  MouseEnter="HyperLinkButton_MouseEnter" MouseLeave="HyperLinkButton_MouseLeave">
                <HyperlinkButton.Background>
                    <ImageBrush ImageSource="/OutageNotices;component/Images/closeButton.png" Stretch="None"/>
                </HyperlinkButton.Background>
                <ToolTipService.ToolTip>
                    <ToolTip Margin="0,20,0,0" Content="Close"/>
                </ToolTipService.ToolTip>
            </HyperlinkButton>
            
        </StackPanel>
 
        <!-- body -->
        <navigation:Frame Source="/Core/CheckingForUpdates.xaml" Grid.Row="2" Grid.Column="2"/>
 
 
    </Grid>
 
</navigation:Page>

This results in a page with and outer border, margin (for icons and menus), and a central area for the frame content.

image

Define an Edge

You’ll often see borderless style windows that have a drop shadow. Take the Zune application for example,

image

Now I don’t think it’s possible to make a Silverlight window appear transparent so this isn’t currently possible (would love to be wrong). But the least you should do is to provide a single pixel border around your window to make sure it stands out from surrounding, similar coloured, windows. Something like,

image

Rather than a single Border I set the colour of the Rectangles that would be used to identify resizing (see below).

Minimize, Maximize, Restore and Close

My icons in the top right are all HyperLinkButton (with icons applied using an ImageBrush) with their own Click event.

The code is pretty straightforward.

private void minimizeButton_Click(object sender, RoutedEventArgs e)
{
    App.Current.MainWindow.WindowState = WindowState.Minimized;
}
 
private void maximizeButton_Click(object sender, RoutedEventArgs e)
{
    App.Current.MainWindow.WindowState = WindowState.Maximized;
 
    // Toggle between restore and maximize buttons
    restoreButton.Visibility = System.Windows.Visibility.Visible;
    maximizeButton.Visibility = System.Windows.Visibility.Collapsed;
 
    // Don't show the resize icon if we're maximized
    resizeButton.Visibility = System.Windows.Visibility.Collapsed;
 
    // Restore to it's original opacity since this won't be reset with the MouseLeave Event
    maximizeButton.Opacity = 0.5;
    
}
 
private void closeButton_Click(object sender, RoutedEventArgs e)
{
    App.Current.MainWindow.Close();
}
 
private void restoreButton_Click(object sender, RoutedEventArgs e)
{
    App.Current.MainWindow.WindowState = WindowState.Normal;
 
    maximizeButton.Visibility = System.Windows.Visibility.Visible;
    restoreButton.Visibility = System.Windows.Visibility.Collapsed;
 
    // Make sure the resize icon is showing 
    resizeButton.Visibility = System.Windows.Visibility.Visible;
 
    // Restore to it's original opacity since this won't be reset with the MouseLeave Event
    restoreButton.Opacity = 0.5;
}

The other thing I did was to change the Opacity of the icons on MouseOver. I started doing this as a Storyboard but to reuse it across the icons would have required code anyway. So I went with a far simpler approach. Each HyperLinkButton points to the same MouseEnter and MouseLeave events which takes care of increasing and decreasing the Opacity. Easy.

private void HyperLinkButton_MouseEnter(object sender, MouseEventArgs e)
{
    HyperlinkButton button = sender as HyperlinkButton;
    button.Opacity = 1;
}
 
private void HyperLinkButton_MouseLeave(object sender, MouseEventArgs e)
{
    HyperlinkButton button = sender as HyperlinkButton;
    button.Opacity = 0.5;
}

So now when the user hovers over the icons darken on MouseEnter (Opacity == 1) and lighten (Opacity == 0.5) on MouseLeave.

image

Resizing

Resizing the window is something else you may want to do to allow the user to drag the edges of the window to resize.

image

My approach was to add Rectangles to each corner and side of the page (in the outer rows/columns of my main Grid). Each Rectangle is wired to the same event handler that examines the Rectangle’s Tag property to determine what value to pass to the DragResize method’s WindowResizeEdge property.

private void border_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
   FrameworkElement border = sender as FrameworkElement;
   App.Current.MainWindow.DragResize((WindowResizeEdge)Enum.Parse(typeof(WindowResizeEdge), border.Tag.ToString(), true));
}

The DragResize method takes care of the rest.

I also added the standard resize icon to the bottom right corner – it too has the appropriate Tag value and is wired to the same event handler as the Rectangles. The only thing to watch out for here is to set the ClickMode property to Hover – otherwise its MouseLeftButtonDown event won’t fire.

One final thing you may want to do is to restrict the minimum size of the window. Unfortunately there is nothing out of the box to do this and the best I could come up with is to handle the master page’s SizeChanged event to reset the window’s dimensions if the users tries to resize the window beyond a defined threshold.

private void Page_SizeChanged(object sender, SizeChangedEventArgs e)
{
    if (e.NewSize.Width < MIN_WIDTH)
    {
        App.Current.MainWindow.Width = MIN_WIDTH;
    }
    if (e.NewSize.Height < MIN_HEIGHT)
    {
        App.Current.MainWindow.Height = MIN_HEIGHT;
    }
}

This approach works although does cause a bit of flickering.

And that’s all there is to creating a professional look and feel to your next OOB application.

Download example.