■はじめに
.NET Core 3.1
とVisual Studio
でコントロールの見栄えを変えたり標準以外のコントロールを使ってみます。
キーワード:ライト/ダークテーマ, NumericUpDown, プログレスリング, ウォーターマーク, トグルスイッチ, InputBox
■環境
- Windows 10
- Visual Studio 2019 Version 16.7.4
- .NET Core 3.1
- MahApps.Metro 2.2.0
■ベース画面作成
こちら を参考に「準備」と「プロジェクトの作成」をしてください。
プロジェクト名はWpfAppThemeSample
にしました。
そして画面を以下のように作成します。
<Window
x:Class="WpfAppThemeSample.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:local="clr-namespace:WpfAppThemeSample"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="MainWindow"
Width="800"
Height="450"
mc:Ignorable="d">
<Window.Resources>
<!-- タブの既定スタイル -->
<Style TargetType="TabItem">
<Setter Property="Width" Value="120" />
</Style>
<!-- ボタンの既定スタイル -->
<Style TargetType="Button">
<Setter Property="Margin" Value="8,8,8,0" />
</Style>
<!-- 画面下部のボタンスタイル -->
<Style x:Key="FooterButton" TargetType="Button">
<Setter Property="Width" Value="100" />
<Setter Property="Margin" Value="8,0,0,0" />
</Style>
<!-- テキストボックスの既定スタイル -->
<Style TargetType="TextBox">
<Setter Property="Margin" Value="8,8,8,0" />
</Style>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!-- テーマ切り替え -->
<GroupBox Margin="8" Header="テーマ">
<StackPanel Orientation="Horizontal">
<RadioButton
Margin="8"
Content="ライト"
IsChecked="True" />
<RadioButton Margin="8" Content="ダーク" />
</StackPanel>
</GroupBox>
<TabControl Grid.Row="1" Margin="8">
<!--#region ■タブ1-->
<TabItem Header="タブ1" IsSelected="True">
<ScrollViewer>
<StackPanel>
<ListBox
Width="200"
Height="80"
Margin="8"
HorizontalAlignment="Left"
SelectedIndex="2">
<ListBoxItem Content="あいうえお" />
<ListBoxItem Content="かきくけこ" />
<ListBoxItem Content="さしすせそ" />
<ListBoxItem Content="たちつてと" />
<ListBoxItem Content="なにぬねの" />
<ListBoxItem Content="はひふへほ" />
</ListBox>
<CheckBox
Margin="8,8,8,0"
Content="チェックボックス"
IsChecked="True" />
<CheckBox Margin="8,8,8,0" Content="チェックボックス" />
<TextBox Text="" />
<TextBox Text="" />
<Button Content="ボタン" />
<Button Content="ボタン" />
<Button Content="ボタン" />
<Button Content="ボタン" />
<Button Content="ボタン" />
<Button Content="ボタン" />
</StackPanel>
</ScrollViewer>
</TabItem>
<!--#endregion-->
<!--#region ■タブ2-->
<TabItem Header="タブ2">
<StackPanel>
<TextBox />
</StackPanel>
</TabItem>
<!--#endregion-->
</TabControl>
<StackPanel
Grid.Row="2"
Margin="8"
HorizontalAlignment="Right"
Orientation="Horizontal">
<Button Content="InputBox" Style="{StaticResource FooterButton}" />
<Button Content="ボタン2" Style="{StaticResource FooterButton}" />
<Button Content="ボタン3" Style="{StaticResource FooterButton}" />
</StackPanel>
</Grid>
</Window>
■デザインの変更
◇ライブラリのインストール
ソリューションエクスプローラーでプロジェクトを右クリック、メニューからNuGetパッケージの管理
を選択します。
参照
タブの検索ボックスにmetro
と入力し、MahApps.Metro
をインストールします。
◇App.xamlの修正
ResourceDictionaryを追加します。
<Application
x:Class="WpfAppThemeSample.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfAppThemeSample"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Themes/Light.Blue.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
◇MainWindow.xamlの修正
xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls"
を追加し、
Window
をmah:MetroWindow
に変更します。
<Window
x:Class="WpfAppThemeSample.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:local="clr-namespace:WpfAppThemeSample"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="MainWindow"
Width="800"
Height="450"
mc:Ignorable="d">
:
</Window>
<mah:MetroWindow
x:Class="WpfAppThemeSample.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:local="clr-namespace:WpfAppThemeSample"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls"
Title="MainWindow"
Width="800"
Height="450"
mc:Ignorable="d">
:
</mah:MetroWindow>
スタイル定義にBasedOn
を追加します。
<!-- タブの既定スタイル -->
<Style BasedOn="{StaticResource MahApps.Styles.TabItem}" TargetType="TabItem">
<Setter Property="Width" Value="120" />
</Style>
<!-- ボタンの既定スタイル -->
<Style BasedOn="{StaticResource MahApps.Styles.Button}" TargetType="Button">
<Setter Property="Margin" Value="8,8,8,0" />
</Style>
<!-- 画面下部のボタンスタイル -->
<Style
x:Key="FooterButton"
BasedOn="{StaticResource MahApps.Styles.Button}"
TargetType="Button">
<Setter Property="Width" Value="100" />
<Setter Property="Margin" Value="8,0,0,0" />
</Style>
<!-- テキストボックスの既定スタイル -->
<Style BasedOn="{StaticResource MahApps.Styles.TextBox}" TargetType="TextBox">
<Setter Property="Margin" Value="8,8,8,0" />
</Style>
◇MainWindow.xaml.csの修正
MainWindow.xaml.cs
ファイルを開き、継承元の記述を消します。
public partial class MainWindow : Window
public partial class MainWindow
■大文字小文字
タイトルバーのMainWindow
と下部ボタンのInputBox
が勝手に大文字に変えられています。
これを無効にして元々設定されたテキストの通りに表示するようにします。
mah:MetroWindow
にTitleCharacterCasing="Normal"
を追加します。
FooterButton
のスタイル定義に<Setter Property="mah:ControlsHelper.ContentCharacterCasing" Value="Normal" />
を追加します。
■ウィンドウスタイル設定
◇最大化ボタン、最小化ボタン
ウィンドウのサイズ変更は有効にしたまま、最大化ボタンと最小化ボタンを非表示にします。
mah:MetroWindow
に
ResizeMode="CanResizeWithGrip"
(サイズ変更グリップ表示)、
ShowMaxRestoreButton="False"
(最大化ボタン非表示)、
ShowMinButton="False"
(最小化ボタン非表示)を追加します。
ここまででXamlは以下のようになっています。
<mah:MetroWindow
x:Class="WpfAppThemeSample.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:local="clr-namespace:WpfAppThemeSample"
xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="MainWindow"
Width="800"
Height="450"
ResizeMode="CanResizeWithGrip"
ShowMaxRestoreButton="False"
ShowMinButton="False"
TitleCharacterCasing="Normal"
mc:Ignorable="d">
<!-- 画面下部のボタンスタイル -->
<Style
x:Key="FooterButton"
BasedOn="{StaticResource MahApps.Styles.Button}"
TargetType="Button">
<Setter Property="Width" Value="100" />
<Setter Property="Margin" Value="8,0,0,0" />
<Setter Property="mah:ControlsHelper.ContentCharacterCasing" Value="Normal" />
</Style>
実行してみます。
タイトルバーとボタンの英字がちゃんと指定された通り、大文字小文字が区別されて表示されました。
最小化ボタンと最大化ボタンも消えました。
ウィンドウの右下にサイズ変更がしやすいようにグリップが表示されました。
◇ウィンドウ縁を光らす
mah:MetroWindow
にGlowBrush="{DynamicResource MahApps.Brushes.Accent}"
を追加します。
ウィンドウの縁がうっすらと光ります。
<mah:MetroWindow
x:Class="WpfAppThemeSample.MainWindow"
:
GlowBrush="{DynamicResource MahApps.Brushes.Accent}"
:
mc:Ignorable="d">
■ダークテーマ
現在の白基調の配色と、黒基調の配色を切り替えられるようにします。
2つのラジオボタンにChecked
イベントの処理を設定します。
<!-- テーマ切り替え -->
<GroupBox Margin="8" Header="テーマ">
<StackPanel Orientation="Horizontal">
<RadioButton
Margin="8"
Checked="ThemeRadioButton_Checked"
Content="ライト"
IsChecked="True" />
<RadioButton
Margin="8"
Checked="ThemeRadioButton_Checked"
Content="ダーク" />
</StackPanel>
</GroupBox>
using ControlzEx.Theming;
using System.Windows;
using System.Windows.Controls;
namespace WpfAppThemeSample
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
}
private void ThemeRadioButton_Checked(object sender, RoutedEventArgs e)
{
if (((RadioButton)sender).Content.ToString() == "ライト")
{
// ライトテーマを設定
ThemeManager.Current.ChangeTheme(this, "Light.Blue");
}
else
{
// ダークテーマを設定
ThemeManager.Current.ChangeTheme(this, "Dark.Blue");
}
}
}
}
実行してみます。
ダーク
のラジオボタンを選択すると黒ベースの配色になりました。
■テキストボックス
タブ2に配置していたテキストボックスを修正します。
◇ウォーターマーク
プレースホルダとも言います。
テキストボックス未入力時に薄く説明文を表示します。
mah:TextBoxHelper.Watermark
に設定した文字列が、テキストボックス空欄時に薄字で表示されます。
◇テキストクリアボタン
mah:TextBoxHelper.ClearTextButton="True"
でテキスト内容をクリアする×
ボタンが表示されます。
<TabItem Header="タブ2">
<StackPanel>
<TextBox
mah:TextBoxHelper.ClearTextButton="True"
mah:TextBoxHelper.Watermark="何か入力してください。"
Text="" />
</StackPanel>
</TabItem>
◇フォーカス時全選択
テキストボックスにフォーカスが来たときに全選択するようにします。
スタイル定義にTextBoxHelper.SelectAllOnFocus
を追加します。
<Window.Resources>
:
<!-- テキストボックスの既定スタイル -->
<Style BasedOn="{StaticResource MahApps.Styles.TextBox}" TargetType="TextBox">
<Setter Property="Margin" Value="8,8,8,0" />
<Setter Property="mah:TextBoxHelper.SelectAllOnFocus" Value="True" />
</Style>
</Window.Resources>
■NumericUpDown
数値入力に適したテキストボックスです。
直接入力することも、+
, -
ボタンで数値を増減することもできます。
タブ2の中のStackPanelに以下を追加します。
<mah:NumericUpDown
Width="100"
Margin="8"
Maximum="999"
Minimum="1"
Value="10" />
■トグルスイッチ
On/Offするスイッチです。
(たまに●を一生懸命ドラッグしている人がいますが、クリックで切り替わります)
タブ2のStackPanelに追加します。
<mah:ToggleSwitch
Margin="8"
Header="何か処理"
IsOn="False"
OffContent="停止"
OnContent="処理中"
Toggled="ToggleSwitch_Toggled" />
private void ToggleSwitch_Toggled(object sender, RoutedEventArgs e)
{
}
[参考]ヘッダーもOn/Offのテキスト切り替えも不要な場合はContent
にテキストを設定します。
<mah:ToggleSwitch Content="電源" IsOn="True"/>
■プログレスリング
タブ2のStackPanelに追加します。
<mah:ProgressRing x:Name="ProgressR" IsActive="False" />
トグルスイッチ切り替え時の処理を記述します。
トグルスイッチがOnになったら処理中表示にするようにします。
private void ToggleSwitch_Toggled(object sender, RoutedEventArgs e)
{
ProgressR.IsActive = ((MahApps.Metro.Controls.ToggleSwitch)sender).IsOn;
}
■InputBox
InputBoxボタンにClick
イベントの処理を追加します。
<Button
Click="InputBoxButton_Click"
Content="InputBox"
Style="{StaticResource FooterButton}" />
<Button Content="ボタン2" Style="{StaticResource FooterButton}" />
<Button Content="ボタン3" Style="{StaticResource FooterButton}" />
MahApps.Metro.Controls.Dialogs
をusingしておきます。
InputBoxButton_Click
定義にasync
を付け足してください。
ShowInputAsync
でInputBoxを表示します。
using MahApps.Metro.Controls.Dialogs;
:
private async void InputBoxButton_Click(object sender, RoutedEventArgs e)
{
var settings = new MetroDialogSettings() { DefaultText = "最初に表示しておく文字列" };
string result = await this.ShowInputAsync(
"タイトル", "何か入力してください。", settings);
if (result == null)
{
// キャンセル
return;
}
else
{
await this.ShowMessageAsync("タイトル", $"「{result}」が入力されました。");
}
}
■タブ
◇タブ切り替え時にアニメーション
TabControl
をmah:MetroAnimatedTabControl
に変更するとタブ切り替え時に中身が少しスライドして表示されるようになります。
<TabControl Grid.Row="1" Margin="8">
<mah:MetroAnimatedTabControl Grid.Row="1" Margin="8">
◇アクティブタブに下線
アクティブなタブに下線を表示します。
タブコントロールにTabControlHelper.Underline
を設定します。
<mah:MetroAnimatedTabControl
Grid.Row="1"
Margin="8"
mah:TabControlHelper.Underlined="SelectedTabItem">