やりたい事
1. 自分でボタンをデザインしたい。
2. 詳細デザインをDictionary.xamlに記述し、"CustomButton"をMainWindow.xamlで使用する。MainWindow.xaml内部をすっきりさせたい。
結果
下の画像が結果である。
一番上(Button1)は、Windowsのチュートリアル[1]に記述されていたもの。二番目(Button2)は、参考文献[2]に記述されていたもの。三番目(Button3)は、デフォルトを表わす。
参考文献
[1] Microsoftのチュートリアル
自分の知識レベルが低いのか? Microsoftのreferenceは分かりにくい。でもこのチュートリアルは分かりやすいです。
[2] XAML UNLEASHED
xamlは、記述方法の慣れが必要で、参考資料が少ないですが、この書籍は分かりやすいと思います。初心者には、こちらを勧めます。しかも、中古本が安い。
詳細
自分でデザインしたボタンをDictionary.xamlに記述します。
ここで、デザインといっても、pngやjpgなどで作った画像データを埋め込むという意味ではありません。
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApp5">
<GradientStopCollection x:Key="MyGlassGradientStopsResource">
<GradientStop Color="WhiteSmoke" Offset="0.2" />
<GradientStop Color="Transparent" Offset="0.4" />
<GradientStop Color="WhiteSmoke" Offset="0.5" />
<GradientStop Color="Transparent" Offset="0.75" />
<GradientStop Color="WhiteSmoke" Offset="0.9" />
<GradientStop Color="Transparent" Offset="1" />
</GradientStopCollection>
<LinearGradientBrush x:Key="MyGlassBrushResource" StartPoint="0,0" EndPoint="1,1" Opacity="0" GradientStops="{StaticResource MyGlassGradientStopsResource}" />
<LinearGradientBrush x:Key="GrayBlueGradientBrush" StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="DarkGray" Offset="0" />
<GradientStop Color="#CCCCFF" Offset="0.5" />
<GradientStop Color="DarkGray" Offset="1" />
</LinearGradientBrush>
<!-- Button1の始まり -->
<Style TargetType="{x:Type Button}" x:Key="ButtonStyle">
<Setter Property="Background" Value="{StaticResource GrayBlueGradientBrush}" />
<Setter Property="Width" Value="80" />
<Setter Property="Margin" Value="10" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}" ClipToBounds="True">
<!-- Outer Rectangle with rounded corners. -->
<Rectangle x:Name="outerRectangle" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" Stroke="{TemplateBinding Background}"
RadiusX="20" RadiusY="20" StrokeThickness="5" Fill="Transparent" />
<!-- Inner Rectangle with rounded corners. -->
<Rectangle x:Name="innerRectangle" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" Stroke="Transparent"
StrokeThickness="20" Fill="{TemplateBinding Background}" RadiusX="20" RadiusY="20" />
<!-- Glass Rectangle -->
<Rectangle x:Name="glassCube" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
StrokeThickness="2" RadiusX="10" RadiusY="10" Opacity="0" Fill="{StaticResource MyGlassBrushResource}"
RenderTransformOrigin="0.5,0.5">
<Rectangle.Stroke>
<LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
<LinearGradientBrush.GradientStops>
<GradientStop Offset="0.0" Color="LightBlue" />
<GradientStop Offset="1.0" Color="Gray" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Rectangle.Stroke>
<Rectangle.RenderTransform>
<TransformGroup>
<ScaleTransform />
<RotateTransform />
</TransformGroup>
</Rectangle.RenderTransform>
<Rectangle.BitmapEffect>
<BevelBitmapEffect />
</Rectangle.BitmapEffect>
</Rectangle>
<!-- Present Text of the button. -->
<DockPanel Name="myContentPresenterDockPanel">
<ContentPresenter x:Name="myContentPresenter" Margin="20" Content="{TemplateBinding Content}" TextBlock.Foreground="Black" />
</DockPanel>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property ="Rectangle.Stroke" TargetName="outerRectangle" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" />
<!-- Sets the glass opacity to 1, therefore, the glass "appears" when user mouses over it. -->
<Setter Property="Rectangle.Opacity" Value="1" TargetName="glassCube" />
<!-- Makes the text slightly blurry as though you were looking at it through blurry glass. -->
<Setter Property="ContentPresenter.BitmapEffect" TargetName="myContentPresenter">
<Setter.Value>
<BlurBitmapEffect Radius="1" />
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="IsFocused" Value="true">
<Setter Property="Rectangle.Opacity" Value="1" TargetName="glassCube" />
<Setter Property="Rectangle.Stroke" TargetName="outerRectangle" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" />
<Setter Property="Rectangle.Opacity" Value="1" TargetName="glassCube" />
</Trigger>
<!-- Animations that start when mouse enters and leaves button. -->
<EventTrigger RoutedEvent="Mouse.MouseEnter">
<EventTrigger.Actions>
<BeginStoryboard Name="mouseEnterBeginStoryboard">
<Storyboard>
<!-- This animation makes the glass rectangle shrink in the X direction. -->
<DoubleAnimation Storyboard.TargetName="glassCube"
Storyboard.TargetProperty= "(Rectangle.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)" By="-0.1" Duration="0:0:0.5" />
<!-- This animation makes the glass rectangle shrink in the Y direction. -->
<DoubleAnimation Storyboard.TargetName="glassCube"
Storyboard.TargetProperty="(Rectangle.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)"
By="-0.1" Duration="0:0:0.5" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
<EventTrigger RoutedEvent="Mouse.MouseLeave">
<EventTrigger.Actions>
<!-- Stopping the storyboard sets all animated properties back to default. -->
<StopStoryboard BeginStoryboardName="mouseEnterBeginStoryboard" />
</EventTrigger.Actions>
</EventTrigger>
<!-- Animation fires when button is clicked, causing glass to spin. -->
<EventTrigger RoutedEvent="Button.Click">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="glassCube"
Storyboard.TargetProperty= "(Rectangle.RenderTransform).(TransformGroup.Children)[1].(RotateTransform.Angle)"
By="360" Duration="0:0:0.5" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- Button1の終わり -->
<!-- Button2の始まり -->
<Style TargetType="Button" x:Key="CustomButton" >
<Setter Property="Margin" Value="10" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}" ClipToBounds="True">
<Ellipse Width="100" Height="100">
<Ellipse.Fill>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Offset="0" Color="Blue"/>
<GradientStop Offset="1" Color="Red"/>
</LinearGradientBrush>
</Ellipse.Fill>
</Ellipse>
<!-- Contentの中身をTemplateの中に埋め込むために以下が必要 -->
<DockPanel Name="myContentPresenterDockPanel1">
<ContentPresenter x:Name="myContentPresenter1" HorizontalAlignment="Center" VerticalAlignment="Center" Content="{TemplateBinding Content}" TextBlock.Foreground="White" />
</DockPanel>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- Button2の終わり-->
</ResourceDictionary>
重要なポイント
Dictonary1.xamlでButtonタイプを継承し、新しくButtonSyleを定義します。
<Style TargetType="{x:Type Button}" x:Key="ButtonStyle">
ボタンに機能を持たせるには、ControlTemplateの下に記述する必要があります。
<ControlTemplate>
<ControlTemplate.Trigger>
<EventTrigger>
-----------
</EventTrigger>
</ControlTemplate.Trigger>
</ControlTemplate>
上記のDictionary1.xamlで記述したButtonStyle(Button1用)のデザインを引継ぎ、MainWindow.xamlで利用する。利用するには、Style="{StaticResource ****}" を使う。
<Button Style="{StaticResource ButtonStyle}" Content="Button1"/>
<Window x:Class="WpfApp5.MainWindow"
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:local="clr-namespace:WpfApp5"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800" Background="Black">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Dictionary1.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<StackPanel HorizontalAlignment="Left">
<Button Style="{StaticResource ButtonStyle}" Content="Button1"/>
<Button Style="{StaticResource CustomButton}" Content="Button2"/>
<Button Content="Button3"/>
</StackPanel>
</Window>
最後に
今回の記事では、ボタンのカスタマイズだったので、xamlのみの変更修正です。
コードビハインドであるMainWindow.xaml.csには、デフォルトの内容です。