【WPF】XAMLでアイコンボタンを作成する方法 | サンプルコード付き

この記事では、WPFでアイコンを表示したいときに使えるアイコンボタンを作成していきます。

この記事で作成するもの

アイコンボタンの画像
アイコンボタン

上記のアイコンボタンを作成します。色を自由に変更することも可能です。

IconButtonコントロールの作成

まず初めにButtonを拡張したIconButtonコントロールを作成します。

using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace NumericUpDown.Controls;

public class IconButton : Button
{
    private static readonly PathGeometry DefaultIcon = new();

    /// <summary>Identifies the <see cref="Icon"/> dependency property.</summary>
    public static readonly DependencyProperty IconProperty = DependencyProperty.Register(
        nameof(Icon),
        typeof(PathGeometry),
        typeof(IconButton),
        new PropertyMetadata(DefaultIcon));

    /// <summary>Identifies the <see cref="IconWidth"/> dependency property.</summary>
    public static readonly DependencyProperty IconWidthProperty = DependencyProperty.Register(
        nameof(IconWidth),
        typeof(double),
        typeof(IconButton));

    /// <summary>Identifies the <see cref="IconHeight"/> dependency property.</summary>
    public static readonly DependencyProperty IconHeightProperty = DependencyProperty.Register(
        nameof(IconHeight),
        typeof(double),
        typeof(IconButton));

    static IconButton()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(IconButton), new FrameworkPropertyMetadata(typeof(IconButton)));
    }

    /// <summary>
    /// Specify the icon data to be displayed on the button.
    /// </summary>
    public PathGeometry Icon
    {
        get => (PathGeometry)this.GetValue(IconProperty);
        set => this.SetValue(IconProperty, value);
    }

    /// <summary>
    /// Specify the width of the icon.
    /// </summary>
    public double IconWidth
    {
        get => (double)this.GetValue(IconWidthProperty);
        set => this.SetValue(IconWidthProperty, value);
    }

    /// <summary>
    /// Specify the height of the icon.
    /// </summary>
    public double IconHeight
    {
        get => (double)this.GetValue(IconHeightProperty);
        set => this.SetValue(IconHeightProperty, value);
    }
}

IconButtonのスタイル定義

スタイルの作成と適用方法の詳しい解説はこちらの記事を参照ください。ここではIconButtonのスタイルを変更してモダンなスタイルを作っていきます。

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:ctrl="clr-namespace:NumericUpDown.Controls">
    <Style x:Key="FocusVisual">
    <Setter Property="Control.Template">
      <Setter.Value>
        <ControlTemplate>
          <Rectangle Margin="0" StrokeDashArray="1 2" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" SnapsToDevicePixels="true" StrokeThickness="1"/>
        </ControlTemplate>
      </Setter.Value>
    </Setter>
  </Style>
  <SolidColorBrush x:Key="Button.Static.Background" Color="Transparent"/>
  <Style TargetType="{x:Type ctrl:IconButton}">
    <Setter Property="FocusVisualStyle" Value="{StaticResource FocusVisual}"/>
    <Setter Property="Background" Value="{StaticResource Button.Static.Background}"/>
    <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
    <Setter Property="BorderThickness" Value="0"/>
    <Setter Property="HorizontalContentAlignment" Value="Center"/>
    <Setter Property="VerticalContentAlignment" Value="Center"/>
    <Setter Property="Padding" Value="0"/>
    <Setter Property="IconWidth" Value="18"/>
    <Setter Property="IconHeight" Value="18"/>
    <Setter Property="Cursor" Value="Hand"/>
    <Setter Property="Template">
      <Setter.Value>
        <ControlTemplate TargetType="{x:Type Button}">
          <Border x:Name="border" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" SnapsToDevicePixels="true">
            <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
              <Viewbox
                Width="{Binding IconWidth, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ctrl:IconButton}}"
                Height="{Binding IconHeight, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ctrl:IconButton}}"
                Stretch="Uniform"
                StretchDirection="Both">
                <Path
                  Fill="{TemplateBinding TextElement.Foreground}"
                  Data="{Binding Icon, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ctrl:IconButton}}"/>
              </Viewbox>
              <ContentPresenter 
                x:Name="contentPresenter" 
                Focusable="False" 
                HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                Margin="{TemplateBinding Padding}"
                RecognizesAccessKey="True"
                SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
            </StackPanel>
          </Border>
          <ControlTemplate.Triggers>
            <Trigger Property="IsEnabled" Value="false">
              <Setter Property="Opacity" Value="0.56"/>
            </Trigger>
          </ControlTemplate.Triggers>
        </ControlTemplate>
      </Setter.Value>
    </Setter>
  </Style>
</ResourceDictionary>

IconButtonの使い方

作成したIconButtonをxamlで使用します。使用方法は下記の通りです。

<ctrl:IconButton
  Icon="{StaticResource icon-search}"
  Foreground="#FF673ab7"/>

ここでctrlはIconButtonがあるnamespaceです。

注意点

  • App.xamlの辞書に、定義したIconButtonのスタイルファイルを登録し忘れないようにする(詳細についてはこちらの記事を参照)
  • アイコンの色はForegroundプロパティを変更することで変えることが可能です。