Creating more complex buttons in XAML

Ever look at a project and wonder how they got a epic button instead of the every day average one?

There is an extremely easy way to do this in Expression Blend.  I’m also going to show the XAML on how to do it by hand however.

Here is a normal button and an ellipse.

image

XAML:

<Ellipse Fill="White" Stroke="Black" Margin="139,68,0,0" 
   HorizontalAlignment="Left" VerticalAlignment="Top" Width="105" Height="105"/>
<Button Margin="248,68,238,0" Content="Button" 
   VerticalAlignment="Top" Height="105"/>

The button acts like a button but I want the ellipse to act like a button.  In Expression Blend, just right click on the Ellipse (or the most outer container element you want to encapsulate), and go to “Make Into Control”

image

You’ll see a new prompt, click Button, and now you have a full blow button that you can style!

image

What Expression Blend did in the background was the following.

XAML:

<Window.Resources>
	<Style x:Key="ButtonStyle1" TargetType="{x:Type Button}">
		<Setter Property="Template">
			<Setter.Value>
				<ControlTemplate TargetType="{x:Type Button}">
					<Grid>
						<Ellipse Fill="White" Stroke="Black"/>
						<ContentPresenter 
							HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
							VerticalAlignment="{TemplateBinding VerticalContentAlignment}" 
							SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" 
							RecognizesAccessKey="True"/>
					</Grid>
					<ControlTemplate.Triggers>
						<Trigger Property="IsFocused" 
							Value="True"/>
						<Trigger Property="IsDefaulted" 
							Value="True"/>
						<Trigger Property="IsMouseOver" 
							Value="True"/>
						<Trigger Property="IsPressed" 
							Value="True"/>
						<Trigger Property="IsEnabled" 
							Value="False"/>
					</ControlTemplate.Triggers>
				</ControlTemplate>
			</Setter.Value>
		</Setter>
	</Style>
</Window.Resources>

And to reference it in the project, put the style on a button.

XAML:

<Button Style="{DynamicResource ButtonStyle1}" Width="105" Height="105" />

To add content changes like a glow on a mouse over or if it is disabled, add a Setter in the Trigger!

For a quick recap here, to do this by hand, you need the following bit of code.  You can also do this at the Application and User Control level as well.

<Window.Resources>
	<Style x:Key="myStyleName" TargetType="{x:Type Button}">
		<Setter Property="Template">
			<Setter.Value>
				<ControlTemplate TargetType="{x:Type Button}">
					<Grid>
						<!-- your XAML goodness -->
					</Grid>
					<ControlTemplate.Triggers>
						<Trigger Property="IsFocused" 
							Value="True"/>
						<Trigger Property="IsDefaulted" 
							Value="True"/>
						<Trigger Property="IsMouseOver" 
							Value="True"/>
						<Trigger Property="IsPressed" 
							Value="True"/>
						<Trigger Property="IsEnabled" 
							Value="False"/>
					</ControlTemplate.Triggers>
				</ControlTemplate>
			</Setter.Value>
		</Setter>
	</Style>
</Window.Resources>

The button is only clickable when you are on the actual ellipse.  Now we can create more complex things like the back button I created for drinktendr:

image

<Button x:Class="drinktendr.Wpf.Controls.BackButton"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
		Style="{DynamicResource arrowBack}" SnapsToDevicePixels="True">
	<Button.Resources>
		<Style x:Key="arrowBack" TargetType="{x:Type Button}">
			<Setter Property="Template">
				<Setter.Value>
					<ControlTemplate TargetType="{x:Type Button}">
						<Grid Background="Black">
							<Viewbox>
								<Grid>
									
									<Path x:Name="arrowTop" Width="262" Height="198" Canvas.Left="45" Canvas.Top="70" 
										Stretch="Fill" StrokeThickness="6" StrokeStartLineCap="Round" StrokeEndLineCap="Round" 
										StrokeLineJoin="Round" Stroke="#FFFF" Fill="#FFF" 
										Data="F1 M 48.5143,170L 144.514,73.9999L 195.514,74L 121.515,150L 304.514,150L 304.514,190L 121.514,190L 195.514,266L 144.514,266L 48.5143,170 Z " RenderTransformOrigin="0.5,0.5">
										<Path.RenderTransform>
											<TransformGroup>
												<ScaleTransform ScaleX="0.7" ScaleY="0.7"/>
												<SkewTransform/>
												<RotateTransform/>
												<TranslateTransform/>
											</TransformGroup>
										</Path.RenderTransform>
									</Path>
									<Path x:Name="arrow" Width="262" Height="198" Canvas.Left="45" Canvas.Top="70" 
										Stretch="Fill" StrokeThickness="6" StrokeStartLineCap="Round" StrokeEndLineCap="Round" 
										StrokeLineJoin="Round" Stroke="#FFFF" Fill="#FFF" 
										Data="F1 M 48.5143,170L 144.514,73.9999L 195.514,74L 121.515,150L 304.514,150L 304.514,190L 121.514,190L 195.514,266L 144.514,266L 48.5143,170 Z " RenderTransformOrigin="0.5,0.5">
										<Path.RenderTransform>
											<TransformGroup>
												<ScaleTransform ScaleX="0.7" ScaleY="0.7"/>
												<SkewTransform/>
												<RotateTransform/>
												<TranslateTransform/>
											</TransformGroup>
										</Path.RenderTransform>
									</Path>
									<Ellipse x:Name="ellipse" Width="340" Height="340" Canvas.Left="0" Canvas.Top="0" Stretch="Fill" StrokeThickness="15" StrokeLineJoin="Round" Opacity=".6" Stroke="#FFFFFF" Fill="#00000000" />
								</Grid>
							</Viewbox>
							<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" RecognizesAccessKey="True"/>
						</Grid>
						<ControlTemplate.Triggers>
							<Trigger Property="IsFocused" Value="True"/>
							<Trigger Property="IsDefaulted" Value="True"/>
							<Trigger Property="IsMouseOver" Value="True">
								<Setter TargetName="ellipse" Property="Opacity" Value="1" />
							</Trigger>
							<Trigger Property="IsPressed" Value="True">
								<Setter TargetName="ellipse" Property="Effect">
									<Setter.Value>
										<DropShadowEffect BlurRadius="50" ShadowDepth="0" RenderingBias="Performance" Color="White" Opacity=".75" />
									</Setter.Value>
								</Setter>
								<Setter TargetName="arrow" Property="Effect">
									<Setter.Value>
										<BlurEffect Radius="30" RenderingBias="Performance" />
									</Setter.Value>
								</Setter>
							</Trigger>
							<Trigger Property="IsEnabled" Value="False"/>
						</ControlTemplate.Triggers>
					</ControlTemplate>
				</Setter.Value>
			</Setter>
		</Style>
	</Button.Resources>
</Button>

rb Dec 12, 2011 @ 5:20 AM

# re: Creating more complex buttons in XAML
nice

bitskull Mar 31, 2012 @ 7:49 AM

# re: Creating more complex buttons in XAML
Good tips, thx!

Boris Sep 5, 2013 @ 6:17 PM

# re: Creating more complex buttons in XAML
A complex code and a strong result. I am impressed by the speed of the script!

Post a Comment

Please add 8 and 1 and type the answer here: