아이콘과 텍스트를 결합한 버튼을 구현할 경우 일반적으로 버튼 템플릿을 재정의하는 방식을 사용합니다. 하지만 일반화된 구현을 원한다면 두 가지 방법이 있습니다:
- 부착 속성(Attached Property) 활용
- 커스텀 컨트롤 개발
부착 속성을 사용하는 방식이 추천됩니다.
1단계: 부착 속성 방식
IconButtonHelper라는 클래스에 Button 타입에 대한 부착 속성을 정의합니다:
public static class IconButtonHelper
{
// 데이터 바인딩 및 스타일링 지원을 위한 의존성 속성
public static readonly DependencyProperty IconSizeProperty =
DependencyProperty.RegisterAttached("IconSize", typeof(int), typeof(IconButtonHelper), new PropertyMetadata(0));
public static int GetIconSize(DependencyObject obj)
{
return (int)obj.GetValue(IconSizeProperty);
}
public static void SetIconSize(DependencyObject obj, int value)
{
obj.SetValue(IconSizeProperty, value);
}
public static readonly DependencyProperty IconGeometryProperty =
DependencyProperty.RegisterAttached("IconGeometry", typeof(Geometry), typeof(IconButtonHelper), new PropertyMetadata(null));
public static Geometry GetIconGeometry(DependencyObject obj)
{
return (Geometry)obj.GetValue(IconGeometryProperty);
}
public static void SetIconGeometry(DependencyObject obj, Geometry value)
{
obj.SetValue(IconGeometryProperty, value);
}
}
스타일 정의:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MyApp.AttachedProperties">
<Style x:Key="IconButtonBase" TargetType="{x:Type Button}">
<Setter Property="BorderThickness" Value="0" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="Padding" Value="10,5" />
<Setter Property="FrameworkElement.Cursor" Value="Hand" />
<Setter Property="UIElement.SnapsToDevicePixels" Value="True" />
<Setter Property="local:IconButtonHelper.IconSize" Value="24" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ButtonBase}">
<Border
Name="border"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}">
<Grid>
<StackPanel
Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Orientation="Vertical">
<Path
Name="iconPath"
Width="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=(local:IconButtonHelper.IconSize)}"
Height="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=(local:IconButtonHelper.IconSize)}"
Margin="0,0,0,5"
Data="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=(local:IconButtonHelper.IconGeometry)}"
Fill="{TemplateBinding Foreground}"
Stretch="Uniform" />
<ContentPresenter
Name="contentPresenter"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Focusable="False"
RecognizesAccessKey="True"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</StackPanel>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="local:IconButtonHelper.IconGeometry" Value="{x:Null}">
<Setter TargetName="iconPath" Property="Visibility" Value="Collapsed" />
</Trigger>
<Trigger Property="Content" Value="{x:Null}">
<Setter TargetName="iconPath" Property="Margin" Value="0" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
사용 예시:
<Button
Width="80"
Height="80"
local:IconButtonHelper.IconGeometry="{StaticResource RunningGeometry}"
local:IconButtonHelper.IconSize="40"
Background="#1e90ff"
Content="실행"
Foreground="White"
Style="{StaticResource IconButtonBase}" />
RunningGeometry 정의:
<PathGeometry x:Key="RunningGeometry">M41.355947 0h572.962133a41.355947 41.355947 0 0 1 41.355947 41.355947v100.037973H0V41.355947A41.355947 41.355947 0 0 1 41.355947 0zM0 210.356907v772.287146A41.355947 41.355947 0 0 0 41.355947 1024h941.288106A41.355947 41.355947 0 0 0 1024 982.644053V210.356907z m851.88608 295.867733L581.973333 776.137387a47.786667 47.786667 0 0 1-66.710186 0.832853 47.786667 47.786667 0 0 1-7.796054-6.294187l-115.083946-115.0976-120.54528 120.558934a47.786667 47.786667 0 0 1-67.611307 0 47.786667 47.786667 0 0 1 0-67.611307l147.12832-147.12832a48.237227 48.237227 0 0 1 13.653333-9.557333 47.786667 47.786667 0 0 1 62.887254 4.096l119.6032 119.507626 236.776106-236.817066a47.786667 47.786667 0 0 1 67.611307 0 47.786667 47.786667 0 0 1 0 67.597653z</PathGeometry>
2단계: 커스텀 컨트롤 방식
추가 내용 예정