Skip to content

Instantly share code, notes, and snippets.

@Nia-TN1012
Last active June 30, 2020 19:10
Show Gist options
  • Save Nia-TN1012/e9207e7fe02d046b3d4d to your computer and use it in GitHub Desktop.
Save Nia-TN1012/e9207e7fe02d046b3d4d to your computer and use it in GitHub Desktop.
Window.ResizeModeと連動するカスタムキャプションボタンを使用したウィンドウです。。(For Qiita : [C# / WPF] WindowChromeを利用したカスタムウィンドウで、Window.ResizeModeと連動するキャプションボタンを作ってみよう)

このGistはQiitaの記事「WindowChromeを利用したカスタムウィンドウで、Window.ResizeModeと連動するキャプションボタンを作ってみよう」( http://qiita.com/nia_tn1012/items/7671dc15496244dcdf75 )で扱っているプログラムです。

◆ ファイルの内容

  • CaptionButtonConverter.cs :

  • MainWindowConverter.cs   :

  • CustomCaption.xaml     :

  • MainWindow.xaml      : メインウィンドウ

  • MainWindow.xaml.cs     : メインウィンドウ(分離コード)

  • Readme.md : このファイル

using System;
using System.Windows;
using System.Windows.Data;
using System.Globalization;
namespace CustomCaption {
/// <summary>
/// ウィンドウのリサイズモードに応じて最大化・最小化ボタンの表示・非表示を設定します。
/// </summary>
public sealed class ResizeCaptionButtonVisibilityConverter : IValueConverter {
public object Convert( object value, Type targetType, object parameter, CultureInfo culture ) =>
// ResizeModeがNoResizeの時はVisibility.Collapsedに、それ以外の時はVisibility.Visibleにします。
value is ResizeMode && ( ResizeMode )value != ResizeMode.NoResize ? Visibility.Visible : Visibility.Collapsed;
public object ConvertBack( object value, Type targetType, object parameter, CultureInfo culture ) => null;
}
/// <summary>
/// ウィンドウのリサイズモードに応じて最大化ボタンの有効・無効を設定します。
/// </summary>
public sealed class MaximizeCaptionButtonEnableConverter : IValueConverter {
public object Convert( object value, Type targetType, object parameter, CultureInfo culture ) =>
// ResizeModeがCanMinimizeの時はfalseに、それ以外の時はtrueにします。
value is ResizeMode && ( ResizeMode )value != ResizeMode.CanMinimize;
public object ConvertBack( object value, Type targetType, object parameter, CultureInfo culture ) => null;
}
/// <summary>
/// ウィンドウサイズに応じて、最大化ボタンの表示文字列を設定します。
/// </summary>
public sealed class MaximizeCaptionButtonContentConverter : IValueConverter {
public object Convert( object value, Type targetType, object parameter, CultureInfo culture ) =>
// Malettフォントでは「1」が「最大化」、「2」が「元に戻す」です。
value is WindowState && ( WindowState )value == WindowState.Maximized ? "2" : "1";
public object ConvertBack( object value, Type targetType, object parameter, CultureInfo culture ) => null;
}
/// <summary>
/// ウィンドウサイズに応じて、最大化ボタンのツールチップを設定します。
/// </summary>
public sealed class MaximizeCaptionButtonTooltipConverter : IValueConverter {
public object Convert( object value, Type targetType, object parameter, CultureInfo culture ) =>
value is WindowState && ( WindowState )value == WindowState.Maximized ? "元に戻す" : "最大化";
public object ConvertBack( object value, Type targetType, object parameter, CultureInfo culture ) => null;
}
}
<ResourceDictionary 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/interactivedesigner/2006"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<!-- カスタムキャプションボタン -->
<Style x:Key="CustomCaptionButtonKey" TargetType="{x:Type Button}">
<!-- キャプションボタンは枠線とフォーカス用枠線を非表示にします -->
<Setter Property="BorderBrush" Value="{x:Null}"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
<!-- Marlettフォント -->
<!-- 最小化:0 / 最大化:1 / リサイズ:2 / 閉じる:r -->
<Setter Property="FontFamily" Value="Marlett"/>
<!-- タブキーによるフォーカスを無効にします -->
<Setter Property="IsTabStop" Value="False"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<!-- 非クライアント領域に置いた時でもヒットテストを有効にします -->
<Setter Property="WindowChrome.IsHitTestVisibleInChrome" Value="True"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid x:Name="Grid">
<Border x:Name="Border"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Padding="{TemplateBinding Padding}"/>
<ContentPresenter HorizontalAlignment="Center"
Margin="{TemplateBinding Padding}"
VerticalAlignment="Center"
FocusVisualStyle="{x:Null}"
RecognizesAccessKey="False"/>
</Grid>
<ControlTemplate.Triggers>
<!-- マウスオーバー時、背景色を少し暗くします -->
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Background" Value="#10000000" TargetName="Border"/>
</Trigger>
<!-- ボタンをクリックした時、背景色を暗くします -->
<Trigger Property="IsPressed" Value="true">
<Setter Property="Background" Value="#40000000" TargetName="Border"/>
</Trigger>
<!-- コントロールが有効の時 -->
<Trigger Property="IsEnabled" Value="true"/>
<!-- コントロールが無効の時、文字色を薄くします -->
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="#40000000"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
<Window x:Class="CustomCaption.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:CustomCaption"
mc:Ignorable="d"
Title="MainWindow" x:Name="MainWindow1"
Height="240" Width="320"
ResizeMode="CanResize"
Icon="small.ico">
<Window.Resources>
<!-- Window用カラー -->
<SolidColorBrush x:Key="MainWindowBackgroundKey" Color="#FFF"/>
<SolidColorBrush x:Key="MainWindowForegroundKey" Color="#111"/>
<SolidColorBrush x:Key="MainWindowBorderBrushKey" Color="Aquamarine"/>
<!-- キャプションボタンのスタイル -->
<Style x:Key="CustomCaptionButtonKey" TargetType="{x:Type Button}"
BasedOn="{StaticResource CustomCaptionButtonKey}">
<Setter Property="Background" Value="{x:Null}"/>
<Setter Property="Foreground" Value="{StaticResource MainWindowForegroundKey}"/>
<Setter Property="Height" Value="30"/>
<Setter Property="Width" Value="40"/>
<Setter Property="FontSize" Value="14"/>
</Style>
<!-- Converter -->
<local:BorderThicknessByWindowStateConverter x:Key="BorderThicknessByWindowStateConverterKey"/>
<local:WindowBorderBrushConverter x:Key="WindowBorderBrushConverterKey"/>
<local:CaptionBarBackgroundConverter x:Key="CaptionBarBackgroundConverterKey"/>
<local:MaximizeCaptionButtonContentConverter x:Key="MaximizeCaptionButtonContentConverterKey"/>
<local:MaximizeCaptionButtonTooltipConverter x:Key="MaximizeCaptionButtonTooltipConverter"/>
<local:MaximizeCaptionButtonEnableConverter x:Key="MaximizeCaptionButtonEnableConverterKey"/>
<local:ResizeCaptionButtonVisibilityConverter x:Key="ResizeCaptionButtonVisibilityConverterKey"/>
</Window.Resources>
<Window.CommandBindings>
<CommandBinding Command="{x:Static SystemCommands.CloseWindowCommand}"
Executed="CloseWindow"/>
<CommandBinding Command="{x:Static SystemCommands.MaximizeWindowCommand}"
Executed="MaximizeOrRestoreWindow"/>
<CommandBinding Command="{x:Static SystemCommands.MinimizeWindowCommand}"
Executed="MinimizeWindow"/>
</Window.CommandBindings>
<WindowChrome.WindowChrome>
<WindowChrome CaptionHeight="30"
ResizeBorderThickness="{x:Static SystemParameters.WindowResizeBorderThickness}"
GlassFrameThickness="0,0,0,1"/>
</WindowChrome.WindowChrome>
<Border BorderThickness="{Binding WindowState, Converter={StaticResource BorderThicknessByWindowStateConverterKey},
ElementName=MainWindow1}"
BorderBrush="{Binding IsActive, Converter={StaticResource WindowBorderBrushConverterKey},
ConverterParameter={StaticResource MainWindowBorderBrushKey}, ElementName=MainWindow1}">
<Grid>
<!-- 上からタイトルバー、コンテンツ -->
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- タイトルバー -->
<Grid Grid.Row="0"
Background="{Binding IsActive, Converter={StaticResource CaptionBarBackgroundConverterKey},
ConverterParameter={StaticResource MainWindowBorderBrushKey}, ElementName=MainWindow1}">
<!-- 左からアイコン、タイトル、コマンドボタン -->
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<!-- アイコンを表示します -->
<Image Grid.Column="0"
Margin="5"
Source="{Binding Icon, ElementName=MainWindow1}"/>
<!-- ウィンドウタイトルを表示します -->
<Grid Grid.Column="1">
<StackPanel HorizontalAlignment="Left"
VerticalAlignment="Center">
<TextBlock Text="{Binding Title, ElementName=MainWindow1}"
Foreground="Black"
Padding="5,0"/>
</StackPanel>
</Grid>
<!-- 最小化、最大化、閉じるボタンを設置します -->
<Grid Grid.Column="2">
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Right"
VerticalAlignment="Center">
<!-- 最小化ボタン -->
<Button Content="0"
Style="{StaticResource CustomCaptionButtonKey}"
Visibility="{Binding ResizeMode, Converter={StaticResource ResizeCaptionButtonVisibilityConverterKey}, ElementName=MainWindow1}"
ToolTip="最小化"
Command="{x:Static SystemCommands.MinimizeWindowCommand}" />
<!-- 最大化ボタン -->
<Button Content="{Binding WindowState,Converter={StaticResource MaximizeCaptionButtonContentConverterKey}, ElementName=MainWindow1}"
Style="{StaticResource CustomCaptionButtonKey}"
IsEnabled="{Binding ResizeMode, Converter={StaticResource MaximizeCaptionButtonEnableConverterKey}, ElementName=MainWindow1}"
Visibility="{Binding ResizeMode, Converter={StaticResource ResizeCaptionButtonVisibilityConverterKey}, ElementName=MainWindow1}"
ToolTip="{Binding WindowState, Converter={StaticResource MaximizeCaptionButtonTooltipConverter}, ElementName=MainWindow1}"
Command="{x:Static SystemCommands.MaximizeWindowCommand}"/>
<!-- 閉じるボタン -->
<Button Content="r"
Style="{StaticResource CustomCaptionButtonKey}"
ToolTip="閉じる"
Command="{x:Static SystemCommands.CloseWindowCommand}"/>
</StackPanel>
</Grid>
</Grid>
<!-- コンテンツ -->
<StackPanel Grid.Row="1"
Margin="30"
TextBlock.FontSize="16">
<TextBlock Text="リサイズモード"/>
<ComboBox x:Name="Mode"
SelectionChanged="ComboBox_SelectionChanged"
SelectedIndex="2">
<ListBoxItem Content="NoResize"/>
<ListBoxItem Content="CanMinimize"/>
<ListBoxItem Content="CanResize"/>
<ListBoxItem Content="CanResizeWithGrip"/>
</ComboBox>
</StackPanel>
</Grid>
</Border>
</Window>
using System.Windows;
using System.Windows.Input;
namespace CustomCaption {
/// <summary>
/// MainWindow.xaml の相互作用ロジック
/// </summary>
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
}
#region キャプションボタンのイベント
/// <summary>
/// 閉じる及び、終了ボタンを押した時のイベントです。
/// </summary>
private void CloseWindow( object sender, ExecutedRoutedEventArgs e ) {
// アプリを終了します。
SystemCommands.CloseWindow( this );
}
/// <summary>
/// 最小化ボタンを押した時のイベントです。
/// </summary>
private void MinimizeWindow( object sender, ExecutedRoutedEventArgs e ) {
// ウインドウを最小化します。
SystemCommands.MinimizeWindow( this );
}
/// <summary>
/// 最大化ボタンを押した時のイベントです。
/// </summary>
private void MaximizeOrRestoreWindow( object sender, ExecutedRoutedEventArgs e ) {
// ウィンドウを最大化( もしくは元のサイズに )します。
if( WindowState != WindowState.Maximized )
SystemCommands.MaximizeWindow( this );
else
SystemCommands.RestoreWindow( this );
}
#endregion
private void ComboBox_SelectionChanged( object sender, System.Windows.Controls.SelectionChangedEventArgs e ) {
MainWindow1.ResizeMode = ( ResizeMode )Mode.SelectedIndex;
}
}
}
using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Data;
using System.Globalization;
namespace CustomCaption {
/// <summary>
/// ウィンドウのアクティブ状態に合わせて、Border.BorderBrush値を調節します。
/// </summary>
public sealed class WindowBorderBrushConverter : IValueConverter {
public object Convert( object value, Type targetType, object parameter, CultureInfo culture ) =>
( value is bool && ( bool )value ) ? parameter as SolidColorBrush : Brushes.LightGray;
public object ConvertBack( object value, Type targetType, object parameter, CultureInfo culture ) => null;
}
/// <summary>
/// ウィンドウサイズに応じて、Border.Thicknessの値を調節します。
/// </summary>
public sealed class BorderThicknessByWindowStateConverter : IValueConverter {
public object Convert( object value, Type targetType, object parameter, CultureInfo culture ) =>
// 最大化時にBorder.Thicknessの値を8.0に設定することで、コントロールが画面の外にはみ出ないようにします。
value is WindowState && ( WindowState )value == WindowState.Maximized ? 8.0 : 1.0;
public object ConvertBack( object value, Type targetType, object parameter, CultureInfo culture ) => null;
}
/// <summary>
/// ウィンドウのアクティブ状態に合わせて、タイトルバーの文字色を調節します。
/// </summary>
public sealed class CaptionForegroundConverter : IValueConverter {
public object Convert( object value, Type targetType, object parameter, CultureInfo culture ) =>
( value is bool && ( bool )value ) ? parameter as SolidColorBrush : Brushes.Gray;
public object ConvertBack( object value, Type targetType, object parameter, CultureInfo culture ) => null;
}
/// <summary>
/// ウィンドウのアクティブ状態に合わせて、タイトルバーのBackground値を調節します。
/// </summary>
public sealed class CaptionBarBackgroundConverter : IValueConverter {
public object Convert( object value, Type targetType, object parameter, CultureInfo culture ) =>
value is bool && ( bool )value ? parameter as SolidColorBrush : Brushes.LightGray;
public object ConvertBack( object value, Type targetType, object parameter, CultureInfo culture ) => null;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment