はじめに
この記事ではプログレスバーの外観のカスタマイズ方法について確認します。
プロジェクトのファイル構成は下図のとおりです。

開発環境は以下のとおりです。
オペレーティングシステム | Windows10 x64 |
Visual Studio | Microsoft Visual Studio Community 2019 Version 16.11.2 |
.NET Framework | 4.7.2 |
サンプルプログラムの動作仕様
カスタマイズした3つのプログレスバーとデフォルトのプログレスバーを表示します。一番下がデフォルトのプログレスバーです。
実行すると下図のとおり、それぞれのプログレスバーが進行していくようにします。



プログレスバーのカスタマイズ(XAML)
カスタマイズするプログレスバーはControlTemplateを使ってApp.xamlのリソースとして定義します。
App.xamlファイルは以下のとおりです。
<Application x:Class="WpfCustomizeControl.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfCustomizeControl"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ControlTemplate TargetType="ProgressBar" x:Key="customProgressBar1">
<Grid>
<Rectangle x:Name="PART_Track">
<Rectangle.Fill>
<LinearGradientBrush EndPoint="1,0">
<GradientStop Color="BlanchedAlmond" Offset="0"/>
<GradientStop Color="Beige" Offset="1"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<Rectangle x:Name="PART_Indicator"
Stroke="Black" StrokeThickness="1"
HorizontalAlignment="Left">
<Rectangle.Fill>
<LinearGradientBrush EndPoint="1,0">
<GradientStop Offset="0" Color="GreenYellow"/>
<GradientStop Offset="1" Color="Yellow"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<TextBlock Text="{Binding Value, RelativeSource={RelativeSource TemplatedParent}, StringFormat=\{0\}%}"
Foreground="{TemplateBinding Foreground}" FontSize="{TemplateBinding FontSize}" FontWeight="Bold"
VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Grid>
</ControlTemplate>
<ControlTemplate TargetType="ProgressBar" x:Key="customProgressBar2">
<Grid>
<Rectangle x:Name="PART_Track">
<Rectangle.Fill>
<LinearGradientBrush EndPoint="1,0">
<GradientStop Color="BlanchedAlmond" Offset="0"/>
<GradientStop Color="Beige" Offset="1"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<Rectangle x:Name="PART_Indicator"
Stroke="Blue" StrokeThickness="0.5"
HorizontalAlignment="Left">
<Rectangle.Fill>
<LinearGradientBrush EndPoint="0.2,1" SpreadMethod="Repeat">
<GradientStop Offset="0" Color="LightCyan"/>
<GradientStop Offset="1" Color="Cyan"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<TextBlock Text="{Binding Value, RelativeSource={RelativeSource TemplatedParent}, StringFormat=\{0\}%}"
Foreground="{TemplateBinding Foreground}" FontSize="{TemplateBinding FontSize}" FontWeight="Bold"
VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Grid>
</ControlTemplate>
<ControlTemplate TargetType="ProgressBar" x:Key="customProgressBar3">
<Grid>
<Ellipse x:Name="PART_Track">
<Ellipse.Fill>
<LinearGradientBrush EndPoint="1,0">
<GradientStop Color="BlanchedAlmond" Offset="0"/>
<GradientStop Color="Beige" Offset="1"/>
</LinearGradientBrush>
</Ellipse.Fill>
</Ellipse>
<Ellipse x:Name="PART_Indicator"
Stroke="Orange" StrokeThickness="3.0"
HorizontalAlignment="Left">
<Ellipse.Fill>
<LinearGradientBrush EndPoint="1,0">
<GradientStop Offset="0" Color="LightPink"/>
<GradientStop Offset="1" Color="DeepPink"/>
</LinearGradientBrush>
</Ellipse.Fill>
</Ellipse>
<TextBlock Text="{Binding Value, RelativeSource={RelativeSource TemplatedParent}, StringFormat=\{0\}%}"
Foreground="{TemplateBinding Foreground}" FontSize="{TemplateBinding FontSize}" FontWeight="Bold"
VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Grid>
</ControlTemplate>
</Application.Resources>
</Application>
MainWindow.xamlファイルは以下のとおりです。
<Window x:Class="WpfCustomizeControl.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:WpfCustomizeControl"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<StackPanel>
<ProgressBar x:Name="progressBar1" Height="30" Margin="20"
Foreground="Blue" FontSize="16"
Template="{StaticResource customProgressBar1}"/>
<ProgressBar x:Name="progressBar2" Height="30" Margin="20"
Foreground="Black" FontSize="18"
Template="{StaticResource customProgressBar2}"/>
<ProgressBar x:Name="progressBar3" Height="30" Margin="20"
Foreground="Black" FontSize="20"
Template="{StaticResource customProgressBar3}"/>
<ProgressBar x:Name="progressBarDefault" Height="30" Margin="20"/>
</StackPanel>
</Window>
プログレスバーの構成
プログレスバーの構成部品はWPFで決められています。
プログレスバーの定義は以下のとおりです。
[System.Windows.TemplatePart(Name="PART_Track", Type=typeof(System.Windows.FrameworkElement))]
[System.Windows.TemplatePart(Name="PART_Indicator", Type=typeof(System.Windows.FrameworkElement))]
[System.Windows.TemplatePart(Name="PART_GlowRect", Type=typeof(System.Windows.FrameworkElement))]
public class ProgressBar : System.Windows.Controls.Primitives.RangeBase

PART_TrackやPART_Indicatorのデータ型はFrameworkElementとなっているため、この派生クラスであるRectangleやEllipseが使用できます。
TemplateBindingマークアップ拡張
App.xamlの各ControlTemplate要素にはTextBlock要素を配置しています。これはプログレスバーの進み具合をパーセント表示したいためです。
TextBlock要素にはTemplateBindingマークアップ拡張によってForegroundプロパティとFontSizeプロパティがバインドされています。
TemplateBindingマークアップ拡張はテンプレートが施されたコントロール(今回の場合はMainWindow.xamlの上から3つのプログレスバー)で指定されたプロパティにバインドするために使用するものです。
一番上のプログレスバーで言うとForegroundプロパティにBlue、FontSizeプロパティに16が指定されていますが、これらの値がそれぞれTextBlockのForegroundプロパティとFontSizeプロパティの値になります。
詳細は以下をご確認ください。

RelativeSourceマークアップ拡張のTemplatedParentモード
同じくTextBlock要素のTextプロパティには、Bindingマークアップ拡張の中でRelativeSourceマークアップ拡張のTemplatedParentモードが指定されています。
TemplatedParentモードは、あるコントロールテンプレート内から、そのコントロールのプロパティをバインドするために使用します。
今回の場合は、コントロールテンプレートのTargetTypeプロパティにProgressBarが指定されているため、Bindingマークアップ拡張のValueプロパティはProgressBarのValueプロパティを指しています。
プログレスバーのカスタマイズ(コードビハインド)
コードビハインドは以下のとおりです。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
namespace WpfCustomizeControl
{
/// <summary>
/// MainWindow.xaml の相互作用ロジック
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromMilliseconds(200);
timer.Tick += OnTimerTick;
timer.Start();
}
private DispatcherTimer timer = null;
private double d = 0.0;
private void OnTimerTick(object sender, EventArgs e)
{
if(d <= progressBar1.Maximum)
{
progressBar1.Value = d;
}
if (d <= progressBar2.Maximum)
{
progressBar2.Value = d;
}
if (d <= progressBar3.Maximum)
{
progressBar3.Value = d;
}
if (d <= progressBarDefault.Maximum)
{
progressBarDefault.Value = d;
}
d++;
}
}
}
タイマーを使って疑似的にプログレスバーを進めています。
今回はプログレスバーの外観をカスタマイズする方法について確認しました。
以上です。
コメント