User Tools

Site Tools


notes:wpf:controls

Controls and Elements in WPF

Canvas

Example: In WPF an element can be positioned in Canvas using the Canvas.Left and Canvas.Top properties as well as the Canvas.Right and Canvas.Bottom properties:

<Canvas>
    <Button Content="Button 1" />
    <Button Content="Button 2" Canvas.Left="30" Canvas.Top="30" />
    <Button Content="Button 3" Canvas.Left="70" Canvas.Top="100" Width="180" Height="40" />
    <Button Content="Button 4" Canvas.Right="30" Canvas.Bottom="30" />
</Canvas>

Example: In WPF the ClipToBounds property clips off elements that stretch beyond Canvas boundaries:

<Canvas Width="15" Height="15" ClipToBounds="True">
    <Rectangle Fill="Crimson" Canvas.Left="11" Canvas.Top="0" Width="10" Height="20" />
    <Path Fill="CornflowerBlue" Stroke="Black" Canvas.Left="1" Canvas.Top="1" 
          StrokeThickness="1" Data="M 0,7 L 5,2 5,5 13,5 13,9 5,9 5,12 z" />
</Canvas>

ClipToBounds set to True:

ClipToBounds set to False:

ComboBox

Example: A simple ComboBox:

  • Changing the default highlight color
  • An ArrayList collection as ItemsSource
  • SelectionChanged and PreviewMouseDown event handlers

<Window x:Class="QuickTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:System="clr-namespace:System;assembly=mscorlib"     
        xmlns:Collections="clr-namespace:System.Collections;assembly=mscorlib"
        Title="MainWindow" Height="150" Width="220">
 
    <Window.Resources>
        <Collections:ArrayList x:Key="ProgrammingLanguages">
            <System:String>C++</System:String>
            <System:String>Java</System:String>
            <System:String>Visual Basic</System:String>
            <System:String>Perl</System:String>
            <System:String>Python</System:String>
        </Collections:ArrayList>
    </Window.Resources>
 
    <StackPanel>
        <ComboBox Name="cboLanguage" 
                  ItemsSource="{StaticResource ProgrammingLanguages}" 
                  SelectedValue="{Binding Path=Java}"
                  Width="100" Margin="15" IsEditable="False"
                  SelectionChanged="cboLanguage_SelectionChanged" 
                  UIElement.PreviewMouseDown="cboLanguage_MouseDown">
            <ComboBox.Resources>
                <SolidColorBrush 
                    x:Key="{x:Static SystemColors.HighlightBrushKey}">LightSteelBlue</SolidColorBrush>
                <SolidColorBrush 
                    x:Key="{x:Static SystemColors.HighlightTextBrushKey}">Black</SolidColorBrush>
            </ComboBox.Resources>
        </ComboBox>
 
    </StackPanel>
</Window>
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
 
namespace QuickTest
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
 
        private void cboLanguage_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            // Obtain a string representing the selected item.
            ComboBox cboLanguage = sender as ComboBox;
            string language = cboLanguage.SelectedItem as string;
 
            // ...
        }
 
        // Select the clicked row in the ListBox.
        private void cboLanguage_MouseDown(object sender, MouseButtonEventArgs e)
        {
            ComboBox cboLanguage = sender as ComboBox;
 
            // ...
        }
    }
}

Example: Change the style of the highlighted item by extending the default template:

<Window x:Class="QuickTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:System="clr-namespace:System;assembly=mscorlib"     
        xmlns:Collections="clr-namespace:System.Collections;assembly=mscorlib"
        Title="MainWindow" Height="200" Width="220">
 
    <Window.Resources>
        <Collections:ArrayList x:Key="ProgrammingLanguages">
            <System:String>C++</System:String>
            <System:String>Java</System:String>
            <System:String>Visual Basic</System:String>
            <System:String>Perl</System:String>
            <System:String>Python</System:String>
        </Collections:ArrayList>
 
        <SolidColorBrush x:Key="SelectedBackgroundBrush" Color="#DDD" />
        <SolidColorBrush x:Key="DisabledForegroundBrush" Color="#888" />
 
        <Style x:Key="{x:Type ComboBoxItem}" TargetType="ComboBoxItem">
            <Setter Property="SnapsToDevicePixels" Value="true"/>
            <Setter Property="OverridesDefaultStyle" Value="true"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="ComboBoxItem">
                        <Border Name="Border" Height="25" Padding="2" SnapsToDevicePixels="true">
                            <ContentPresenter VerticalAlignment="Center" Margin="3,0,0,0" />
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsHighlighted" Value="true">
                                <Setter TargetName="Border" 
                                        Property="Background" 
                                        Value="{StaticResource SelectedBackgroundBrush}"/>
                            </Trigger>
                            <Trigger Property="IsEnabled" Value="false">
                                <Setter Property="Foreground" 
                                        Value="{StaticResource DisabledForegroundBrush}"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>
 
    <StackPanel>
        <ComboBox Name="cboLanguage" 
                  ItemsSource="{StaticResource ProgrammingLanguages}" 
                  Width="100" Margin="15" IsEditable="False" />
    </StackPanel>
</Window>

Example: Change the colors of the highlighted item by redefining the colors in resources:

<ComboBox>
    <ComboBox.Resources>
        <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}">LightSteelBlue</SolidColorBrush>
        <SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}">Black</SolidColorBrush>
    </ComboBox.Resources>
</ComboBox>

DataGrid

Example: An editable DataGrid:

Read-only mode:

Edit mode (after double clicking a cell):

<Window x:Class="TestApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="TestApp"
        Width="300" Height="300">
    <DataGrid x:Name="GridComments"
              GridLinesVisibility="Horizontal" 
              HorizontalGridLinesBrush="LightGray" 
              AutoGenerateColumns="False" 
              HeadersVisibility="Row" 
              RowHeight="20">
        <DataGrid.Columns>
            <DataGridTextColumn Header="Comment" Binding="{Binding Path=Text}" Width="Auto">
                <DataGridTextColumn.ElementStyle>
                    <Style TargetType="TextBlock">
                        <Setter Property="Background" Value="AliceBlue" />
                        <Setter Property="TextWrapping" Value="Wrap" />
                    </Style>
                </DataGridTextColumn.ElementStyle>
                <DataGridTextColumn.EditingElementStyle>
                    <Style TargetType="TextBox">
                        <Setter Property="Background" Value="Yellow" />
                        <Setter Property="TextWrapping" Value="Wrap" />
                        <Setter Property="AcceptsReturn" Value="True" />
                    </Style>
                </DataGridTextColumn.EditingElementStyle>
            </DataGridTextColumn>
        </DataGrid.Columns>
    </DataGrid>
</Window>
using System.Collections.Generic;
using System.Windows;
 
namespace TestApp
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            GridComments.ItemsSource = GetComments();
        }
 
        private IList<Comment> GetComments()
        {
            return new List<Comment>() 
            { 
                new Comment { ID = 1, Text="Comment#1"},
                new Comment { ID = 2, Text="Comment#2"},
                new Comment { ID = 3, Text="Comment#3"}
            };
        }
    }
 
    public class Comment
    {
        public int ID { get; set; }
        public string Text { get; set; }
    }
}

DatePicker

Example: A simple DatePicker:

<Window x:Class="QuickTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="150" Width="200">
 
    <Window.Resources>
        <Style x:Key="DatePickerStyle" TargetType="DatePicker">
            <Setter Property="Background" Value="White"/>
            <Setter Property="Margin" Value="2"/>
            <Setter Property="Padding" Value="2"/>
            <Setter Property="BorderBrush" Value="Gray"/>
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="UseLayoutRounding" Value="True"/>
        </Style>
 
        <Style x:Key="CalendarStyle" TargetType="Calendar">
            <Setter Property="Margin" Value="2"/>
            <Setter Property="Padding" Value="2"/>
            <Setter Property="BorderBrush" Value="SteelBlue"/>
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="UseLayoutRounding" Value="True"/>
        </Style>
    </Window.Resources>
 
    <StackPanel>
        <TextBlock Padding="3">Date Visited:</TextBlock>
        <DatePicker Name="pickerDateVisited" Style="{StaticResource DatePickerStyle}" 
                    SelectedDate="{Binding Path=DateInspected}" SelectedDateFormat="Short" 
                    CalendarStyle="{StaticResource CalendarStyle}" />
    </StackPanel>
</Window>

DockPanel

DockPanel aligns elements against an edge of the panel. The order of the elements is important.

Example: A simple DockPanel:

<DockPanel>
    <Label Content="Top" DockPanel.Dock="Top" Background="Red"/>
    <Label Content="Left" DockPanel.Dock="Left" Background="Gray"/>
    <Label Content="Right" DockPanel.Dock="Right" Background="Cyan"/>
    <Label Content="Bottom" DockPanel.Dock="Bottom" Background="Magenta"/>
    <Label Content="" Background="Yellow"/> <!-- fills the remaining area -->
</DockPanel>

Example: DockPanel.LastChildFill determines behaviour of the last child in DockPanel:

<DockPanel LastChildFill="False">
    <Label Content="Top" DockPanel.Dock="Top" Background="Red"/>
    <Label Content="Left" DockPanel.Dock="Left" Background="Gray"/>
    <Label Content="Right" DockPanel.Dock="Right" Background="Cyan"/>
    <Label Content="Bottom" DockPanel.Dock="Bottom" Background="Magenta"/>
    <Label Content="Content" Background="Yellow"/> <!-- does not fill the remaining area -->
</DockPanel>

Example: Nested DockPanels:

<DockPanel>
    <TextBlock DockPanel.Dock="Top" Background="LightBlue">Header</TextBlock>
    <TextBlock DockPanel.Dock="Bottom" Background="LightYellow">Footer</TextBlock>
    <TextBlock DockPanel.Dock="Left" Background="Lavender">Side Bar</TextBlock>
    <!-- fills the remaining area of the outer panel -->
    <DockPanel Background="Bisque">
        <StackPanel DockPanel.Dock="Top" Orientation="Horizontal" Margin="5">
            <Button HorizontalAlignment="Left" Height="20" Width="70" Margin="5">Button1</Button>
            <Button HorizontalAlignment="Left" Height="20" Width="70" Margin="5">Button2</Button>
        </StackPanel>
        <!-- fills the remaining area of the inner panel -->
        <TextBlock Background="LightGreen">Content</TextBlock>
    </DockPanel>
</DockPanel>

Example: A typical layout using a DockPanel:

<Window x:Class="QuickTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="400">
 
    <Window.Resources>
        <!-- Title -->
        <Style x:Key="TitleText" TargetType="TextBlock">
            <Setter Property="FontSize" Value="26"/>
            <Setter Property="Margin" Value="5"/>
            <Setter Property="Padding" Value="3,3,0,0"/>
            <Setter Property="Foreground" Value="SteelBlue" />
        </Style>
 
        <!-- Toolbar elements styles -->
        <Style x:Key="ToolbarText" TargetType="TextBlock">
            <Setter Property="FontSize" Value="14"/>
            <Setter Property="Margin" Value="2"/>
        </Style>
        <Style x:Key="ToolbarComboBox" TargetType="ComboBox">
            <Setter Property="FontSize" Value="14"/>
        </Style>
        <Style x:Key="ToolbarButton" TargetType="Button">
            <Setter Property="Height" Value="25"/>
            <Setter Property="Margin" Value="5,1"/>
            <Setter Property="Padding" Value="1"/>
            <Setter Property="MinWidth" Value="70"/>
            <Setter Property="FontSize" Value="12"/>
            <Setter Property="Background" >
                <Setter.Value>
                    <LinearGradientBrush StartPoint="0,0" EndPoint="0,1" >
                        <GradientStop Color="DarkGray"  Offset="0.2"/>
                        <GradientStop Color="LightGray" Offset="0.85"/>
                        <GradientStop Color="DarkGray" Offset="1"/>
                    </LinearGradientBrush>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>
 
    <DockPanel LastChildFill="True">
 
        <!-- Toolbar -->
        <ToolBarTray DockPanel.Dock="Top">
            <ToolBar>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="Company: " 
                        Style="{StaticResource ToolbarText}" 
                        Margin="3,3,0,3" 
                        VerticalAlignment="Center" />
                    <ComboBox x:Name="cboCompanies" 
                        DisplayMemberPath="CompanyName" 
                        Style="{StaticResource ToolbarComboBox}" 
                        Width="150" Height="25" IsEditable="False" />
                    <Button x:Name="btnDetails" 
                        Style="{StaticResource ToolbarButton}">Details</Button>
                </StackPanel>
            </ToolBar>
        </ToolBarTray>
 
        <!-- Title -->
        <TextBlock DockPanel.Dock="Top" Style="{StaticResource TitleText}">Contacts</TextBlock>
 
        <!-- Status bar -->
        <StatusBar DockPanel.Dock="Bottom" xml:space="preserve">WBS - 2012</StatusBar>
 
        <!-- Contact list -->
        <ListBox x:Name="ContactsList" ItemsSource="{Binding}" 
            Height="Auto" Width="Auto" 
            HorizontalContentAlignment="Stretch" 
            BorderThickness="1" 
            ScrollViewer.CanContentScroll="False">
 
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Grid Margin="5,0,0,0">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition></ColumnDefinition>
                            <ColumnDefinition></ColumnDefinition>
                            <ColumnDefinition></ColumnDefinition>
                        </Grid.ColumnDefinitions>
                        <Grid.RowDefinitions>
                            <RowDefinition></RowDefinition>
                        </Grid.RowDefinitions>
 
                        <TextBlock Grid.Column="0" Text="{Binding Path=Name}" />
                        <TextBlock Grid.Column="1" Text="{Binding Path=Email}" />
                        <TextBlock Grid.Column="2" Text="{Binding Path=Phone}" />
                    </Grid>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </DockPanel>
</Window>

GridSplitter

Example: A vertical GridSplitter:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition></RowDefinition>
        <RowDefinition></RowDefinition>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition MinWidth="100"></ColumnDefinition>
        <ColumnDefinition Width="Auto"></ColumnDefinition>
        <ColumnDefinition MinWidth="30"></ColumnDefinition>
    </Grid.ColumnDefinitions>
 
    <TextBlock Grid.Row="0" Grid.Column="0" Margin="3" Background="Blue" />
    <TextBlock Grid.Row="0" Grid.Column="2" Margin="3" Background="Red" />
    <TextBlock Grid.Row="1" Grid.Column="0" Margin="3" Background="Yellow" />
    <TextBlock Grid.Row="1" Grid.Column="2" Margin="3" Background="Green" />
 
    <GridSplitter Grid.Row="0" Grid.Column="1" Grid.RowSpan="2" Width="2" 
                  VerticalAlignment="Stretch" HorizontalAlignment="Center" 
                  ShowsPreview="False" Background="Black" />
</Grid>

Splitter moved maximum to the left:

Splitter moved maximum to the right:

GridSplitter gudelines:

  • Place the GridSplitter in a Grid cell. Reserve a dedicated column or a row for the GridSplitter, with a Height or Width set to Auto.
  • Stretch the GridSplitter across an entire row or column using the RowSpan or ColumnSpan properties.
  • Supply values for the VerticalAlignment, HorizontalAlignment, and Width (or Height).
  • For a vertical splitter: set VerticalAlignment to Stretch, HorizontalAlignment to Center, and Width to a fixed value.
  • For a horizontal splitter: set HorizontalAlignment to Stretch, VerticalAlignment to Center, and Height to a fixed value.
  • Optionally, change the resizing behavior using the ResizeDirection and ResizeBehavior properties of the GridSplitter.

GridSplitter properties:

  • ShowsPreview = false: when the splitter bar is dragged, the columns are resized immediately.
  • ShowsPreview = true: when the splitter bar is dragged, a gray line follows the mouse pointer. The columns are resized once the mouse is released.
  • DragIncrement: determines how smooth the splitter bar is moved.
  • Background: a color or a gradient of the splitter bar.

Example:

<DockPanel>
    <Grid HorizontalAlignment="Left"
            DockPanel.Dock="Top">
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <Menu Grid.Column="0" Padding="3">
            <MenuItem Header="File">
                <MenuItem Header="New Contact" />
                <MenuItem Header="New Group" />
                <Separator />
                <MenuItem Header="Properties" />
                <MenuItem Header="Delete" />
                <MenuItem Header="Import">
                    <MenuItem Header="Address book (WAB)..." />
                    <MenuItem Header="Business card vCard)..." />
                </MenuItem>
                <Separator />
                <MenuItem Header="Exit" InputGestureText="Alt-F4" >
                    <MenuItem.ToolTip>
                        <ToolTip>
                            Click here to exit
                        </ToolTip>
                    </MenuItem.ToolTip>
                </MenuItem>
            </MenuItem>
        </Menu>
        <Menu Grid.Column="1" Padding="3">
            <MenuItem Header="Edit">
                <MenuItem Command="ApplicationCommands.Copy"/>
                <MenuItem Command="ApplicationCommands.Paste"/>
            </MenuItem>
        </Menu>
    </Grid>
 
    <!-- Just to provide some content for the DockPanel -->
    <Grid>
    </Grid>
</DockPanel>   

Example: A Popup control displayed beneath a TextBlock 'CommentLabel':

<Window x:Class="QuickTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="200" Width="200">
 
    <StackPanel>
        <TextBlock TextWrapping="Wrap">
            <Run TextDecorations="Underline" MouseEnter="ShowCommentsPopup_MouseEnter">Enter comments</Run>
        </TextBlock>
 
        <TextBlock x:Name="CommentLabel"  Margin="3" />
 
        <Popup x:Name="CommentPopup" 
           Width="{Binding Path=Width,RelativeSource={RelativeSource AncestorType={x:Type Window}}}" 
           Height="Auto" 
           VerticalOffset="0" 
           HorizontalOffset="-5"
           StaysOpen="False" 
           Placement="Bottom" 
           PopupAnimation="Slide" 
           AllowsTransparency="True"
           PlacementTarget="{Binding ElementName=CommentLabel}">
 
            <!-- Elements go here -->
            <Border BorderBrush="Navy" BorderThickness="1" Background="AntiqueWhite">
                <StackPanel Orientation="Horizontal">
                    <TextBlock Margin="3">Comment:</TextBlock>
                    <TextBox Width="100" Margin="3"></TextBox>
                </StackPanel>
            </Border>
        </Popup>
 
    </StackPanel>
 
</Window>

The IsOpen property of the Popup control:

using System.Windows;
using System.Windows.Input;
 
namespace QuickTest
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
 
        private void ShowCommentsPopup_MouseEnter(object sender, MouseEventArgs e)
        {
            // Show the popup.
            CommentPopup.IsOpen = true;
        }
    }
}

Shapes

A few characteristics of shapes:

  • Shapes are classes that represent lines, ellipses, rectangles, and polygons known as drawing primitives.
  • Shapes derive from FrameworkElement.
  • Canvas is the most useful container to layout the shapes.
  • Shapes support the same events as other elements.
  • Every shape derives from the abstract System.Windows.Shapes.Shape class.
  • You need to set the Stroke or Fill property, otherwise your shape won't appear.
  • In WPF we can combine paths. A result is another path defined by vectors. Operations: unite, intersect, subtract, exclude overlap.

Shape classes:

  • Line
  • Ellipse
  • Rectangle
  • Polyline - a connected series of straight lines
  • Polygon - a closed shape made up of a connected series of straight lines
  • Path - can combine basic shapes in a single element

Shape properties:

  • Fill
  • Stroke
  • StrokeThickness
  • StrokeStartLineCap, StrokeEndLineCap - have an effect only for the Line, Polyline, and Path.
  • StrokeDashArray, StrokeDashOffset, and StrokeDashCap
  • StrokeLineJoin, StrokeMiterLimit - affect the vertices where different lines meet, such as the corners of a Rectangle
  • Stretch
  • DefiningGeometry - a Geometry object that describes the coordinates and size of a shape.
  • GeometryTransform - a Transform object that allows you to skew, rotate, or displace a shape.
  • RenderedGeometry - a Geometry object that describes the final, rendered shape.

Example: A rectangle and an ellipse:

<Window x:Class="QuickTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="300" Width="300">
 
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="*"></RowDefinition>
        </Grid.RowDefinitions>
 
        <StackPanel>
            <Ellipse Fill="AliceBlue" Stroke="Navy" 
                 Width="100" Height="50" Margin="5" HorizontalAlignment="Left"></Ellipse>
            <Rectangle Fill="AntiqueWhite" Stroke="Blue" 
                 Width="100" Height="50" Margin="5" HorizontalAlignment="Left"></Rectangle>
        </StackPanel>
 
        <Canvas Grid.Row="1">
            <Ellipse Fill="AliceBlue" Stroke="Blue" Canvas.Left="80" Canvas.Top="60"
                 Width="100" Height="50"></Ellipse>
            <Rectangle Fill="AntiqueWhite" Stroke="Blue" Canvas.Left="30" Canvas.Top="40"                 
                 Width="100" Height="50"></Rectangle>
        </Canvas>
    </Grid>
</Window>

Example: Rectangles with rounded corners:

<Window x:Class="QuickTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="420" Width="300">
 
    <StackPanel HorizontalAlignment="Center">
        <TextBlock Margin="5">RadiusX="5" RadiusY="5"</TextBlock>
        <Rectangle Fill="Yellow" Stroke="Black" RadiusX="5" RadiusY="5"
            Width="100" Height="60" Margin="5" HorizontalAlignment="Left">
        </Rectangle>
 
        <TextBlock Margin="5">RadiusX="10" RadiusY="10"</TextBlock>
        <Rectangle Fill="Blue" Stroke="Black" RadiusX="10" RadiusY="10"
            Width="100" Height="60" Margin="5" HorizontalAlignment="Left"></Rectangle>
 
        <TextBlock Margin="5">RadiusX="10" RadiusY="25"</TextBlock>
        <Rectangle Fill="Green" Stroke="Black" RadiusX="10" RadiusY="25"
            Width="100" Height="60" Margin="5" HorizontalAlignment="Left"></Rectangle>
 
        <TextBlock Margin="5">RadiusX="100" RadiusY="60"</TextBlock>
        <Rectangle Fill="Red" Stroke="Black" RadiusX="100" RadiusY="60"
            Width="100" Height="60" Margin="5" HorizontalAlignment="Left"></Rectangle>
    </StackPanel>
 
</Window>

Example: An ellipse filling up the window. Because we don't provide the Height and Width properties, the shape is sized to its container:

<Window x:Class="QuickTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="300" Width="300">
 
    <Grid>
        <Ellipse Fill="Aquamarine" Stroke="Navy"></Ellipse>
    </Grid>
 
</Window>

SharedSizeGroup

A shared size group matches the definition of a column (or a row) in one grid to a column (or a row) in another grid. In order to enable this feature a container has to have the property Grid.IsSharedSizeScope set to True and the values of the property SharedSizeGroup of the grids have to match.

Example: Use SharedSizeGroup to share definition of the first column in two separate grids:

<Grid Grid.IsSharedSizeScope="True" ShowGridLines="True"> <!-- IsSharedSizeScope -->
    <Grid.RowDefinitions>
        <RowDefinition />
        <RowDefinition />
    </Grid.RowDefinitions>
 
    <Grid Grid.Row="0">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" SharedSizeGroup="LabelColumn" /> <!-- SharedSizeGroup -->
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
 
        <Label Grid.Column="0" Margin="3" Background="AliceBlue">Some more text goes here</Label>
        <Label Grid.Column="1" Margin="3" Background="AntiqueWhite">Hello</Label>
        <Label Grid.Column="2" Margin="3" Background="Beige">Here</Label>
    </Grid>
 
    <Grid Grid.Row="1">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" SharedSizeGroup="LabelColumn" /> <!-- SharedSizeGroup -->
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
 
        <Label Grid.Column="0" Margin="3" Background="FloralWhite">Little text</Label>
        <Label Grid.Column="1" Margin="3" Background="Cornsilk">Hello here</Label>
    </Grid>
</Grid>

The same code but with sharing definition of different columns (the first column in the top grid and the second column in the bottom grid):

Example: A shared size scope column and a scrollbar:

<DockPanel DockPanel.Dock="Bottom" Grid.IsSharedSizeScope="True">
 
    <DockPanel.Resources>
        <Style TargetType="{x:Type TextBlock}">
            <Setter Property="Margin" Value="5,3" />
        </Style>
    </DockPanel.Resources>
 
    <!-- Header grid -->
    <Grid DockPanel.Dock="Top">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="Auto" SharedSizeGroup="Author" />
            <ColumnDefinition Width="Auto" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
 
        <Border Grid.Column="0" Grid.Row="0" Background="LightGray" BorderBrush="Gray" BorderThickness="1">
            <TextBlock>Title</TextBlock>
        </Border>
        <Border Grid.Column="1" Grid.Row="0" Grid.ColumnSpan="2" 
                Background="LightGray" BorderBrush="Gray" BorderThickness="1">
            <TextBlock>Author</TextBlock>
        </Border>
 
        <!-- A "dummy" scroll bar just to get its width in order to properly size columns -->
        <ScrollBar Grid.Column="3" Orientation="Vertical" Visibility="Hidden" Height="20" />
    </Grid>
 
    <!-- Content grid -->
    <ScrollViewer>
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="Auto" SharedSizeGroup="Author" />
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
 
            <TextBlock Grid.Column="0" Grid.Row="0">The C++ Programming Language</TextBlock>
            <TextBlock Grid.Column="1" Grid.Row="0">Bjarne Stroustrup</TextBlock>
 
            <TextBlock Grid.Column="0" Grid.Row="1">Effective C++</TextBlock>
            <TextBlock Grid.Column="1" Grid.Row="1">Scott Meyers</TextBlock>
 
            <TextBlock Grid.Column="0" Grid.Row="2">The C++ Standard Library</TextBlock>
            <TextBlock Grid.Column="1" Grid.Row="2">Nicolai M. Josuttis</TextBlock>
 
            <TextBlock Grid.Column="0" Grid.Row="3">C++ in a Nutshell</TextBlock>
            <TextBlock Grid.Column="1" Grid.Row="3">Ray Lischner</TextBlock>
 
            <TextBlock Grid.Column="0" Grid.Row="4">C++ Pocket Reference</TextBlock>
            <TextBlock Grid.Column="1" Grid.Row="4">Kyle Loudon</TextBlock>
        </Grid>
    </ScrollViewer>
 
</DockPanel>

The same code but with Grid.IsSharedSizeScope set to False which makes the two grids inconsistent:

Example: A SharedSizeGroup and GridSplitter placed in the header of the first grid:

<DockPanel DockPanel.Dock="Bottom" Grid.IsSharedSizeScope="True">
 
    <DockPanel.Resources>
        <Style TargetType="{x:Type TextBlock}">
            <Setter Property="Margin" Value="5,3" />
        </Style>
    </DockPanel.Resources>
 
    <!-- Header grid -->
    <Grid DockPanel.Dock="Top">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" MinWidth="80" SharedSizeGroup="Title" />
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
 
        <Border Grid.Column="0" Grid.Row="0" Background="LightGray" BorderBrush="Gray" BorderThickness="1">
            <TextBlock>Title</TextBlock>
        </Border>
        <Border Grid.Column="2" Grid.Row="0" Background="LightGray" BorderBrush="Gray" BorderThickness="1">
            <TextBlock>Author</TextBlock>
        </Border>
 
        <GridSplitter Grid.Column="1" Grid.Row="0" Width="2" 
                VerticalAlignment="Stretch" HorizontalAlignment="Center" 
                ShowsPreview="False" Background="Black" />
 
    </Grid>
 
    <!-- Content grid -->
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" SharedSizeGroup="Title" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
 
        <Rectangle Grid.Column="1" Grid.RowSpan="5" Fill="AliceBlue"></Rectangle>
 
        <TextBlock Grid.Column="0" Grid.Row="0">The C++ Programming Language</TextBlock>
        <TextBlock Grid.Column="1" Grid.Row="0">Bjarne Stroustrup</TextBlock>
 
        <TextBlock Grid.Column="0" Grid.Row="1">Effective C++</TextBlock>
        <TextBlock Grid.Column="1" Grid.Row="1">Scott Meyers</TextBlock>
 
        <TextBlock Grid.Column="0" Grid.Row="2">The C++ Standard Library</TextBlock>
        <TextBlock Grid.Column="1" Grid.Row="2">Nicolai M. Josuttis</TextBlock>
 
        <TextBlock Grid.Column="0" Grid.Row="3">C++ in a Nutshell</TextBlock>
        <TextBlock Grid.Column="1" Grid.Row="3">Ray Lischner</TextBlock>
 
        <TextBlock Grid.Column="0" Grid.Row="4">C++ Pocket Reference</TextBlock>
        <TextBlock Grid.Column="1" Grid.Row="4">Kyle Loudon</TextBlock>
 
    </Grid>
</DockPanel>

This allows users to resize the header and the entire column underneath:

Specialized Containers

WPF specialized containers:

  • GroupBox - GroupBox has no built-in functionality. It's just a header and a rectangle.
  • TabItem - The TabItem represents a page in a TabControl.
  • Expander - The Expander wraps a region of content that the user can show or hide by clicking a small arrow button.

GroupBox:

<GroupBox Header="Testing..." Padding="3">
    <StackPanel>
        <RadioButton Margin="3">Blue</RadioButton>
        <RadioButton Margin="3">Green</RadioButton>
        <RadioButton Margin="3">Red</RadioButton>
    </StackPanel>
</GroupBox>

TabControl/TabItem:

<TabControl Margin="3">
 
    <TabItem Header="Panel 1">
        <StackPanel Margin="3">
            <CheckBox Margin="3">Red</CheckBox>
            <CheckBox Margin="3">Green</CheckBox>
            <CheckBox Margin="3">Yellow</CheckBox>
        </StackPanel>
    </TabItem>
 
    <TabItem Header="Panel 2">
    ...
    </TabItem>
 
</TabControl>

Expander:

<StackPanel>
    <Expander Padding="5" Header="Test1">
        <Button Padding="3">Button1</Button>
    </Expander>
    <Expander Padding="5" Header="Test2">
        <TextBlock>Testing...</TextBlock>
    </Expander>
</StackPanel>

ToolTip

Tooltips are content controls. It is possible to tweak timing settings of the ToolTip to control how quickly it appears and disappears.

Commonly used properties of the ToolTip:

  • Background
  • Padding
  • Font
  • HasDropShadow
  • Placement - mouse location, absolute screen coordinates, or relative to an element set using PlacementTarget
  • HorizontalOffset, VerticalOffset, PlacementRectangle
  • CustomPopupPlacementCallback - positioning a tooltip using code
  • IsEnabled and IsOpen - controlling the tooltip in code

Some properties of the ToolTipService:

  • InitialShowDelay
  • ShowDuration
  • BetweenShowDelay - a time during which the user can move between tooltips without experiencing the InitialShowDelay
  • ToolTip - sets the tooltip as a piece of text
  • HasDropShadow
  • ShowOnDisabled - determines the tooltip behavior when the associated element is disabled
  • Placement, PlacementTarget, PlacementRectangle, and VerticalOffset
<!-- Example #1 -->
<Button ToolTip="This is my tooltip">I have a tooltip</Button>
 
<!-- Example #2 -->
<Button>
    <Button.ToolTip>
        <StackPanel>
            <TextBlock>This is </TextBlock>
            <TextBlock>tooltip</TextBlock>
        </StackPanel>
    </Button.ToolTip>
    <Button.Content>My Button</Button.Content>
</Button>
 
<!-- Example #3 -->
<Button>
    <Button.ToolTip>
        <ToolTip Background="Azure" Foreground="Crimson" HasDropShadow="False">
            <StackPanel>
                <TextBlock>This is </TextBlock>
                <TextBlock>tooltip</TextBlock>
            </StackPanel>
        </ToolTip>
    </Button.ToolTip>
    <Button.Content>My Button</Button.Content>
</Button>
 
<!-- Example #4 -->
<Button ToolTipService.InitialShowDelay="1">
...
</Button>
 
<!-- Example #5 -->
<Button ToolTip="Some text" ToolTipService.Placement="Bottom">my button</Button>

UniformGrid

UniformGrid arranges elements in a table and forces all cells to have the same size. It doesn't support predefined columns and rows; the cells are placed in the grid in the order they are defined.

<UniformGrid Rows="3" Columns="3">
    <TextBlock Background="Green" />
    <TextBlock Background="Red" />
    <TextBlock Background="Green" />
    <TextBlock Background="Red" />
    <TextBlock Background="Green" />
    <TextBlock Background="Red" />
    <TextBlock Background="Green" />
    <TextBlock Background="Red" />
    <TextBlock Background="Green" />
</UniformGrid>

WrapPanel

Example: A simple WrapPanel:

<Window x:Class="QuickTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="120" Width="350">
 
    <!-- Orientation="Horizontal" is the default value -->
    <WrapPanel Orientation="Horizontal" Margin="3">
        <TextBlock VerticalAlignment="Bottom" Background="Aquamarine">Bottom Text</TextBlock>
        <TextBlock VerticalAlignment="Center" Background="BurlyWood">Center Text</TextBlock>
        <TextBlock VerticalAlignment="Top" Background="AliceBlue">Top Text</TextBlock>
        <Button MinHeight="50">Button1</Button>
        <Button>Button2</Button>
        <Button Height="50">Button3</Button>
    </WrapPanel>
</Window>
notes/wpf/controls.txt · Last modified: 2017/03/23 by leszek