This commit is contained in:
GG Z
2025-07-31 20:12:24 +08:00
parent 4f6cd2137c
commit f209e7d3ad
426 changed files with 15854 additions and 6612 deletions

View File

@@ -0,0 +1,717 @@
using System;
using System.Collections;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media;
using AntDesignWPF.Contracts;
using AntDesignWPF.Microsoft.Windows.Shell;
using Standard;
namespace AntDesignWPF.Controls
{
[TemplatePart(Name = PART_TitleBarThumb, Type = typeof(Thumb))]
[TemplatePart(Name = PART_TitleBar, Type = typeof(UIElement))]
[TemplatePart(Name = PART_Icon, Type = typeof(FrameworkElement))]
[TemplatePart(Name = PART_LeftWindowCommands, Type = typeof(WindowCommands))]
[TemplatePart(Name = PART_Title, Type = typeof(UIElement))]
[TemplatePart(Name = PART_RightWindowCommands, Type = typeof(WindowCommands))]
[TemplatePart(Name = PART_WindowButtons, Type = typeof(WindowButtons))]
public class AntWindow : Window
{
#region Fields
private const string PART_TitleBarThumb = "PART_TitleBarThumb";
private const string PART_TitleBar = "PART_TitleBar";
private const string PART_Icon = "PART_Icon";
private const string PART_LeftWindowCommands = "PART_LeftWindowCommands";
private const string PART_Title = "PART_Title";
private const string PART_RightWindowCommands = "PART_RightWindowCommands";
private const string PART_WindowButtons = "PART_WindowButtons";
private Thumb titleBarThumb;
private UIElement titleBar;
private FrameworkElement icon;
internal ContentPresenter leftWindowCommands;
private UIElement title;
internal ContentPresenter rightWindowCommands;
internal ContentPresenter windowButtons;
#endregion
#region Properties
public static readonly DependencyProperty IgnoreTaskbarProperty =
DependencyProperty.Register("IgnoreTaskbar", typeof(bool), typeof(AntWindow), new PropertyMetadata(false));
/// <summary>
/// Gets/sets whether the window will ignore (and overlap) the taskbar when maximized.
/// </summary>
public bool IgnoreTaskbar
{
get { return (bool)GetValue(IgnoreTaskbarProperty); }
set { SetValue(IgnoreTaskbarProperty, value); }
}
public static readonly DependencyProperty ShowSystemMenuProperty =
DependencyProperty.Register("ShowSystemMenu", typeof(bool), typeof(AntWindow), new PropertyMetadata(false));
/// <summary>
/// Gets/sets if the the system menu should popup on right click.
/// </summary>
public bool ShowSystemMenu
{
get { return (bool)GetValue(ShowSystemMenuProperty); }
set { SetValue(ShowSystemMenuProperty, value); }
}
public static readonly DependencyProperty IsDraggableProperty =
DependencyProperty.Register("IsDraggable", typeof(bool), typeof(AntWindow), new PropertyMetadata(true));
/// <summary>
/// Gets/sets if the the allow drag window
/// </summary>
public bool IsDraggable
{
get { return (bool)GetValue(IsDraggableProperty); }
set { SetValue(IsDraggableProperty, value); }
}
public static readonly DependencyProperty UseNoneWindowStyleProperty =
DependencyProperty.Register("UseNoneWindowStyle", typeof(bool), typeof(AntWindow), new PropertyMetadata(false, OnUseNoneWindowStyleChanged));
/// <summary>
/// Gets/sets whether the WindowStyle is None or not.
/// </summary>
public bool UseNoneWindowStyle
{
get { return (bool)GetValue(UseNoneWindowStyleProperty); }
set { SetValue(UseNoneWindowStyleProperty, value); }
}
private static void OnUseNoneWindowStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue != e.OldValue)
{
(d as AntWindow).ToggleNoneWindowStyle((bool)e.NewValue);
}
}
private void ToggleNoneWindowStyle(bool useNoneWindowStyle)
{
SetVisibiltyForTitleBarElements(!useNoneWindowStyle && TitleBarHeight > 0);
}
protected IntPtr CriticalHandle
{
get
{
var value = typeof(Window).GetProperty("CriticalHandle", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(this, new object[0]);
return (IntPtr)value;
}
}
public static readonly DependencyProperty TitleBarHeightProperty =
DependencyProperty.Register("TitleBarHeight", typeof(double), typeof(AntWindow), new PropertyMetadata(30d, OnTitleBarHeightChanged));
/// <summary>
/// Gets/sets the TitleBar height.
/// </summary>
public double TitleBarHeight
{
get { return (double)GetValue(TitleBarHeightProperty); }
set { SetValue(TitleBarHeightProperty, value); }
}
private static void OnTitleBarHeightChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
{
var window = (AntWindow)dependencyObject;
if (e.NewValue != e.OldValue)
{
window.SetVisibiltyForTitleBarElements((int)e.NewValue > 0);
}
}
public static readonly DependencyProperty TitleBarForegroundProperty =
DependencyProperty.Register("TitleBarForeground", typeof(Brush), typeof(AntWindow));
/// <summary>
/// Gets/sets the foreground brush of the title bar.
/// </summary>
public Brush TitleBarForeground
{
get { return (Brush)GetValue(TitleBarForegroundProperty); }
set { SetValue(TitleBarForegroundProperty, value); }
}
public static readonly DependencyProperty TitleBarBackgroundProperty =
DependencyProperty.Register("TitleBarBackground", typeof(Brush), typeof(AntWindow), new PropertyMetadata(Brushes.Transparent));
/// <summary>
/// Gets/sets the background brush of the title bar.
/// </summary>
public Brush TitleBarBackground
{
get { return (Brush)GetValue(TitleBarBackgroundProperty); }
set { SetValue(TitleBarBackgroundProperty, value); }
}
public static readonly DependencyProperty ShowIconProperty =
DependencyProperty.Register("ShowIcon", typeof(bool), typeof(AntWindow), new PropertyMetadata(true, OnShowIconChanged));
/// <summary>
/// Gets/sets whether the titlebar icon is visible or not.
/// </summary>
public bool ShowIcon
{
get { return (bool)GetValue(ShowIconProperty); }
set { SetValue(ShowIconProperty, value); }
}
private static void OnShowIconChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue != e.OldValue)
{
(d as AntWindow).SetVisibiltyForIcon();
}
}
public static readonly DependencyProperty IconTemplateProperty =
DependencyProperty.Register("IconTemplate", typeof(DataTemplate), typeof(AntWindow), new PropertyMetadata(null));
/// <summary>
/// Gets/sets the icon content template to show a custom icon.
/// </summary>
public DataTemplate IconTemplate
{
get { return (DataTemplate)GetValue(IconTemplateProperty); }
set { SetValue(IconTemplateProperty, value); }
}
public static readonly DependencyProperty TitleCharacterCasingProperty =
DependencyProperty.Register("TitleCharacterCasing", typeof(CharacterCasing), typeof(AntWindow),
new FrameworkPropertyMetadata(CharacterCasing.Normal, FrameworkPropertyMetadataOptions.Inherits | FrameworkPropertyMetadataOptions.AffectsMeasure),
value => CharacterCasing.Normal <= (CharacterCasing)value && (CharacterCasing)value <= CharacterCasing.Upper);
/// <summary>
/// Character casing of the title
/// </summary>
public CharacterCasing TitleCharacterCasing
{
get { return (CharacterCasing)GetValue(TitleCharacterCasingProperty); }
set { SetValue(TitleCharacterCasingProperty, value); }
}
public static readonly DependencyProperty TitleAlignmentProperty =
DependencyProperty.Register("TitleAlignment", typeof(HorizontalAlignment), typeof(AntWindow), new PropertyMetadata(HorizontalAlignment.Stretch, OnTitleAlignmentChanged));
public HorizontalAlignment TitleAlignment
{
get { return (HorizontalAlignment)GetValue(TitleAlignmentProperty); }
set { SetValue(TitleAlignmentProperty, value); }
}
private static void OnTitleAlignmentChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
{
if (dependencyObject is AntWindow window)
{
window.SizeChanged -= window.OnSizeChanged;
if ((HorizontalAlignment)e.NewValue == HorizontalAlignment.Center)
{
window.SizeChanged += window.OnSizeChanged;
}
}
}
public static readonly DependencyProperty TitleTemplateProperty =
DependencyProperty.Register("TitleTemplate", typeof(DataTemplate), typeof(AntWindow), new PropertyMetadata(null));
/// <summary>
/// Gets/sets the title content template to show a custom title.
/// </summary>
public DataTemplate TitleTemplate
{
get { return (DataTemplate)GetValue(TitleTemplateProperty); }
set { SetValue(TitleTemplateProperty, value); }
}
public static readonly DependencyProperty LeftWindowCommandsProperty =
DependencyProperty.Register("LeftWindowCommands", typeof(WindowCommands), typeof(AntWindow), new PropertyMetadata(null, UpdateLogicalChilds));
/// <summary>
/// Gets/sets the left window commands that hosts the user commands.
/// </summary>
public WindowCommands LeftWindowCommands
{
get { return (WindowCommands)GetValue(LeftWindowCommandsProperty); }
set { SetValue(LeftWindowCommandsProperty, value); }
}
public static readonly DependencyProperty RightWindowCommandsProperty =
DependencyProperty.Register("RightWindowCommands", typeof(WindowCommands), typeof(AntWindow), new PropertyMetadata(null, UpdateLogicalChilds));
/// <summary>
/// Gets/sets the right window commands that hosts the user commands.
/// </summary>
public WindowCommands RightWindowCommands
{
get { return (WindowCommands)GetValue(RightWindowCommandsProperty); }
set { SetValue(RightWindowCommandsProperty, value); }
}
public static readonly DependencyProperty WindowButtonsProperty =
DependencyProperty.Register("WindowButtons", typeof(WindowButtons), typeof(AntWindow), new PropertyMetadata(null, UpdateLogicalChilds));
/// <summary>
/// Gets/sets the window button commands that hosts the min/max/close commands.
/// </summary>
public WindowButtons WindowButtons
{
get { return (WindowButtons)GetValue(WindowButtonsProperty); }
set { SetValue(WindowButtonsProperty, value); }
}
private static void UpdateLogicalChilds(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
{
if (!(dependencyObject is AntWindow window))
{
return;
}
if (e.OldValue is FrameworkElement oldChild)
{
window.RemoveLogicalChild(oldChild);
}
if (e.NewValue is FrameworkElement newChild)
{
window.AddLogicalChild(newChild);
// Yes, that's crazy. But we must do this to enable all possible scenarios for setting DataContext
// in a Window. Without set the DataContext at this point it can happen that e.g. a Flyout
// doesn't get the same DataContext.
// So now we can type
//
// InitializeComponent();
// DataContext = new MainViewModel();
//
// or
//
// DataContext = new MainViewModel();
// InitializeComponent();
//
newChild.DataContext = window.DataContext;
}
}
#endregion
#region Constructors
static AntWindow()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(AntWindow), new FrameworkPropertyMetadata(typeof(AntWindow)));
}
public AntWindow()
{
//SetResourceReference(StyleProperty, typeof(AntdWindow));
DataContextChanged += OnDataContextChanged;
}
#endregion
#region LogicalTree
protected override IEnumerator LogicalChildren
{
get
{
// cheat, make a list with all logical content and return the enumerator
ArrayList children = new ArrayList { Content };
if (LeftWindowCommands != null)
{
children.Add(LeftWindowCommands);
}
if (RightWindowCommands != null)
{
children.Add(RightWindowCommands);
}
if (WindowButtons != null)
{
children.Add(WindowButtons);
}
return children.GetEnumerator();
}
}
#endregion
#region Overrides
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
titleBarThumb = GetTemplateChild(PART_TitleBarThumb) as Thumb;
titleBar = GetTemplateChild(PART_TitleBar) as UIElement;
icon = GetTemplateChild(PART_Icon) as FrameworkElement;
title = GetTemplateChild(PART_Title) as UIElement;
leftWindowCommands = GetTemplateChild(PART_LeftWindowCommands) as ContentPresenter;
rightWindowCommands = GetTemplateChild(PART_RightWindowCommands) as ContentPresenter;
windowButtons = GetTemplateChild(PART_WindowButtons) as ContentPresenter;
if (LeftWindowCommands == null)
LeftWindowCommands = new WindowCommands();
if (RightWindowCommands == null)
RightWindowCommands = new WindowCommands();
if (WindowButtons == null)
WindowButtons = new WindowButtons();
LeftWindowCommands.ParentWindow = this;
RightWindowCommands.ParentWindow = this;
WindowButtons.ParentWindow = this;
var windowChrome = GetValue(WindowChrome.WindowChromeProperty) as WindowChrome;
if (windowChrome != null)
{
BindingOperations.SetBinding(
windowChrome,
WindowChrome.IgnoreTaskbarProperty,
new Binding { Path = new PropertyPath(IgnoreTaskbarProperty), Source = this, Mode = BindingMode.OneWay }
);
}
ToggleNoneWindowStyle(UseNoneWindowStyle);
}
#endregion
#region Private Methods
private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
// add these controls to the window with AddLogicalChild method.
// This has the side effect that the DataContext doesn't update, so do this now here.
if (LeftWindowCommands != null) LeftWindowCommands.DataContext = DataContext;
if (RightWindowCommands != null) RightWindowCommands.DataContext = DataContext;
if (WindowButtons != null) WindowButtons.DataContext = DataContext;
}
private void OnSizeChanged(object sender, RoutedEventArgs e)
{
// this all works only for centered title
if (TitleAlignment != HorizontalAlignment.Center) return;
// Half of this Window
var halfDistance = ActualWidth / 2;
// Distance between center and left/right
var distanceToCenter = title.DesiredSize.Width / 2;
// Distance between right edge from LeftWindowCommands to left window side
var distanceFromLeft = icon.ActualWidth + LeftWindowCommands.ActualWidth;
// Distance between left edge from RightWindowCommands to right window side
var distanceFromRight = WindowButtons.ActualWidth + RightWindowCommands.ActualWidth;
// Margin
const double horizontalMargin = 5.0;
var dLeft = distanceFromLeft + distanceToCenter + horizontalMargin;
var dRight = distanceFromRight + distanceToCenter + horizontalMargin;
// TODO They should also change when the layout changes.
if ((dLeft < halfDistance) && (dRight < halfDistance))
{
Grid.SetColumn(title, 0);
Grid.SetColumnSpan(title, 5);
}
else
{
Grid.SetColumn(title, 2);
Grid.SetColumnSpan(title, 1);
}
}
private void SetVisibiltyForTitleBarElements(bool visible)
{
var value = visible ? Visibility.Visible : Visibility.Collapsed;
titleBar?.SetCurrentValue(VisibilityProperty, value);
title?.SetCurrentValue(VisibilityProperty, value);
SetVisibiltyForIcon();
leftWindowCommands?.SetValue(VisibilityProperty, value);
rightWindowCommands?.SetValue(VisibilityProperty, value);
windowButtons?.SetCurrentValue(VisibilityProperty, value);
SetWindowEvents();
}
private void SetVisibiltyForIcon()
{
if (icon == null) return;
icon.Visibility = ShowIcon && !UseNoneWindowStyle && TitleBarHeight > 0 ? Visibility.Visible : Visibility.Collapsed;
}
private void SetWindowEvents()
{
// clear all event handlers first
ClearWindowEvents();
// set mouse down/up for icon
if (icon != null && icon.Visibility == Visibility.Visible)
{
icon.MouseLeftButtonDown += OnIconMouseLeftButtonDown;
icon.MouseRightButtonUp += OnThumbMouseRightButtonUp;
}
if (titleBarThumb != null)
{
titleBarThumb.PreviewMouseLeftButtonUp += OnThumbPreviewMouseLeftButtonUp;
titleBarThumb.DragDelta += OnThumbDragDelta;
titleBarThumb.MouseDoubleClick += OnThumbMouseDoubleClick;
titleBarThumb.MouseRightButtonUp += OnThumbMouseRightButtonUp;
}
var thumbContentControl = title as IThumb;
if (thumbContentControl != null)
{
thumbContentControl.PreviewMouseLeftButtonUp += OnThumbPreviewMouseLeftButtonUp;
thumbContentControl.DragDelta += OnThumbDragDelta;
thumbContentControl.MouseDoubleClick += OnThumbMouseDoubleClick;
thumbContentControl.MouseRightButtonUp += OnThumbMouseRightButtonUp;
}
// handle size if we have a Grid for the title (e.g. clean window have a centered title)
if (title != null && TitleAlignment == HorizontalAlignment.Center)
{
SizeChanged += OnSizeChanged;
}
}
private void ClearWindowEvents()
{
// clear all event handlers first:
if (titleBarThumb != null)
{
titleBarThumb.PreviewMouseLeftButtonUp -= OnThumbPreviewMouseLeftButtonUp;
titleBarThumb.DragDelta -= OnThumbDragDelta;
titleBarThumb.MouseDoubleClick -= OnThumbMouseDoubleClick;
titleBarThumb.MouseRightButtonUp -= OnThumbMouseRightButtonUp;
}
var thumbContentControl = title as IThumb;
if (thumbContentControl != null)
{
thumbContentControl.PreviewMouseLeftButtonUp -= OnThumbPreviewMouseLeftButtonUp;
thumbContentControl.DragDelta -= OnThumbDragDelta;
thumbContentControl.MouseDoubleClick -= OnThumbMouseDoubleClick;
thumbContentControl.MouseRightButtonUp -= OnThumbMouseRightButtonUp;
}
if (icon != null)
{
icon.MouseLeftButtonDown -= OnIconMouseLeftButtonDown;
icon.MouseRightButtonUp -= OnThumbMouseRightButtonUp;
}
SizeChanged -= OnSizeChanged;
}
private void OnIconMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (!ShowSystemMenu) return;
if (e.ClickCount == 2)
{
Close();
} else
{
System.Windows.SystemCommands.ShowSystemMenu(this, PointToScreen(new Point(0, TitleBarHeight)));
}
}
private void OnThumbPreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
DoThumbPreviewMouseLeftButtonUp(this, e);
}
private void OnThumbDragDelta(object sender, DragDeltaEventArgs e)
{
DoThumbDragDelta(sender as IThumb, this, e);
}
private void OnThumbMouseDoubleClick(object sender, MouseButtonEventArgs e)
{
DoThumbMouseDoubleClick(this, e);
}
private void OnThumbMouseRightButtonUp(object sender, MouseButtonEventArgs e)
{
DoThumbMouseRightButtonUp(this, e);
}
internal static void DoThumbPreviewMouseLeftButtonUp(AntWindow window, MouseButtonEventArgs e)
{
if (e.Source == e.OriginalSource)
{
Mouse.Capture(null);
}
}
internal static void DoThumbDragDelta(IThumb thumb, AntWindow window, DragDeltaEventArgs e)
{
if (thumb == null)
{
throw new ArgumentNullException(nameof(thumb));
}
if (window == null)
{
throw new ArgumentNullException(nameof(window));
}
// drag only if IsDraggable is set to true
if (!window.IsDraggable ||
(!(Math.Abs(e.HorizontalChange) > 2) && !(Math.Abs(e.VerticalChange) > 2)))
{
return;
}
// tage from DragMove internal code
window.VerifyAccess();
//var cursorPos = WinApiHelper.GetPhysicalCursorPos();
// if the window is maximized dragging is only allowed on title bar (also if not visible)
var maximized = window.WindowState == WindowState.Maximized;
var isMouseOnTitlebar = Mouse.GetPosition(thumb).Y <= window.TitleBarHeight && window.TitleBarHeight > 0;
if (!isMouseOnTitlebar && maximized) return;
#pragma warning disable 618
// for the touch usage
Win32.UnsafeNativeMethods.ReleaseCapture();
#pragma warning restore 618
if (maximized)
{
//var cursorXPos = cursorPos.x;
EventHandler windowOnStateChanged = null;
windowOnStateChanged = (sender, args) =>
{
//window.Top = 2;
//window.Left = Math.Max(cursorXPos - window.RestoreBounds.Width / 2, 0);
window.StateChanged -= windowOnStateChanged;
if (window.WindowState == WindowState.Normal)
{
Mouse.Capture(thumb, CaptureMode.Element);
}
};
window.StateChanged += windowOnStateChanged;
}
var criticalHandle = window.CriticalHandle;
// DragMove works too
// window.DragMove();
// instead this 2 lines
#pragma warning disable 618
NativeMethods.SendMessage(criticalHandle, WM.SYSCOMMAND, (IntPtr)SC.MOUSEMOVE, IntPtr.Zero);
NativeMethods.SendMessage(criticalHandle, WM.LBUTTONUP, IntPtr.Zero, IntPtr.Zero);
#pragma warning restore 618
}
/// <summary>
/// Change window state on MouseDoubleClick
/// </summary>
/// <param name="window"></param>
/// <param name="e"></param>
internal static void DoThumbMouseDoubleClick(AntWindow window, MouseButtonEventArgs e)
{
// restore/maximize only with left button
if (e.ChangedButton == MouseButton.Left)
{
// we can maximize or restore the window if the title bar height is set (also if title bar is hidden)
var canResize = window.ResizeMode == ResizeMode.CanResizeWithGrip || window.ResizeMode == ResizeMode.CanResize;
var mousePos = Mouse.GetPosition(window);
var isMouseOnTitlebar = mousePos.Y <= window.TitleBarHeight && window.TitleBarHeight > 0;
if (canResize && isMouseOnTitlebar)
{
if (window.WindowState == WindowState.Normal)
{
System.Windows.SystemCommands.MaximizeWindow(window);
}
else
{
System.Windows.SystemCommands.RestoreWindow(window);
}
e.Handled = true;
}
}
}
/// <summary>
/// Show system menu on MouseRightButtonUp
/// </summary>
/// <param name="window"></param>
/// <param name="e"></param>
internal static void DoThumbMouseRightButtonUp(AntWindow window, MouseButtonEventArgs e)
{
if (window.ShowSystemMenu)
{
// show menu only if mouse pos is on title bar or if we have a window with none style and no title bar
var mousePos = e.GetPosition(window);
if ((mousePos.Y <= window.TitleBarHeight && window.TitleBarHeight > 0) || (window.UseNoneWindowStyle && window.TitleBarHeight <= 0))
{
System.Windows.SystemCommands.ShowSystemMenu(window, window.PointToScreen(mousePos));
}
}
}
/// <summary>
/// Gets the template child with the given name.
/// </summary>
/// <typeparam name="T">The interface type inheirted from DependencyObject.</typeparam>
/// <param name="name">The name of the template child.</param>
internal T GetPart<T>(string name) where T : class
{
return GetTemplateChild(name) as T;
}
/// <summary>
/// Gets the template child with the given name.
/// </summary>
/// <param name="name">The name of the template child.</param>
internal DependencyObject GetPart(string name)
{
return GetTemplateChild(name);
}
#endregion
}
}

View File

@@ -0,0 +1,202 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:AntdShell="clr-namespace:AntDesignWPF.Microsoft.Windows.Shell"
xmlns:Shell="clr-namespace:Microsoft.Windows.Shell"
xmlns:controls="clr-namespace:AntDesignWPF.Controls"
xmlns:helpers="clr-namespace:AntDesignWPF.Helpers"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/AntDesignWPF;component/Themes/Converters.xaml" />
<!--<ResourceDictionary Source="pack://application:,,,/AntDesignWPF;component/Themes/Dark.xaml" />-->
</ResourceDictionary.MergedDictionaries>
<Style TargetType="{x:Type Thumb}" x:Key="Ant.TitleBarThumb">
<Setter Property="Background" Value="Transparent" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid Background="{TemplateBinding Background}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type controls:AntWindow}">
<Setter Property="WindowStyle" Value="None" />
<Setter Property="SnapsToDevicePixels" Value="True" />
<!--<Setter Property="Foreground" Value="{DynamicResource AntDesign.Brush.TextPrimary}" />-->
<Setter Property="Icon" Value="{StaticResource AntDesignDrawingImage}" />
<!--<Setter Property="FontFamily" Value="{DynamicResource FontFamily}" />-->
<Setter Property="FontSize" Value="{DynamicResource FontSizeBase}" />
<!--<Setter Property="Template" Value="{StaticResource Ant.WindowTemplate}" />-->
<Setter Property="Background" Value="{DynamicResource AntDesign.Brush.BackgroundContainer}" />
<Setter Property="TitleBarForeground" Value="{DynamicResource AntDesign.Brush.TextOnPrimary}" />
<Setter Property="TitleBarBackground" Value="{DynamicResource AntDesign.Brush.Primary}" />
<Setter Property="IconTemplate">
<Setter.Value>
<DataTemplate>
<Image
Source="{TemplateBinding Content}"
Stretch="None"
VerticalAlignment="Center" />
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="TitleTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock
FontSize="{DynamicResource FontSizeSmall}"
Margin="8,0"
Text="{TemplateBinding Content}"
TextTrimming="CharacterEllipsis"
VerticalAlignment="Center" />
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="AntdShell:WindowChrome.WindowChrome">
<Setter.Value>
<AntdShell:WindowChrome
CaptionHeight="0"
CornerRadius="0"
GlassFrameThickness="0 0 0 0.1"
UseAeroCaptionButtons="False" />
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type controls:AntWindow}">
<Border
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding helpers:AntControl.CornerRadius}"
LayoutTransform="{TemplateBinding LayoutTransform}"
Margin="{Binding WindowNonClientFrameThickness, Source={x:Static Shell:SystemParameters2.Current}}"
RenderTransform="{TemplateBinding RenderTransform}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
UseLayoutRounding="True">
<AdornerDecorator>
<Grid UseLayoutRounding="False" x:Name="LayoutRoot">
<Grid.ColumnDefinitions>
<!-- icon -->
<ColumnDefinition Width="Auto" />
<!-- left window commands -->
<ColumnDefinition Width="Auto" />
<!-- title -->
<ColumnDefinition Width="*" />
<!-- right window commands -->
<ColumnDefinition Width="Auto" />
<!-- min,max,close buttons -->
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- title bar -->
<Rectangle
Fill="{TemplateBinding TitleBarBackground}"
Focusable="False"
Grid.ColumnSpan="5"
Height="{TemplateBinding TitleBarHeight}"
StrokeThickness="0"
x:Name="PART_TitleBar" />
<!--
Note:
thumb 元素必须放在标题栏背景之后,
否则会影响双击标题栏窗口以最大化
-->
<controls:Thumb
Grid.ColumnSpan="5"
Style="{StaticResource Ant.TitleBarThumb}"
x:Name="PART_TitleBarThumb" />
<!-- icon -->
<ContentPresenter
Content="{TemplateBinding Icon}"
ContentTemplate="{TemplateBinding IconTemplate}"
Focusable="False"
Height="{TemplateBinding TitleBarHeight}"
VerticalAlignment="Top"
x:Name="PART_Icon" />
<!-- 左侧窗口命令 -->
<ContentPresenter
Content="{TemplateBinding LeftWindowCommands}"
Focusable="False"
Grid.Column="1"
Height="{TemplateBinding TitleBarHeight}"
VerticalAlignment="Top"
x:Name="PART_LeftWindowCommands" />
<!-- title -->
<controls:ThumbContentControl
Content="{TemplateBinding Title}"
ContentCharacterCasing="{TemplateBinding TitleCharacterCasing}"
ContentTemplate="{TemplateBinding TitleTemplate}"
Focusable="False"
Foreground="{TemplateBinding TitleBarForeground}"
Grid.Column="2"
Height="{TemplateBinding TitleBarHeight}"
HorizontalAlignment="{TemplateBinding TitleAlignment}"
x:Name="PART_Title" />
<!-- 右侧窗口命令 -->
<ContentPresenter
Content="{TemplateBinding RightWindowCommands}"
Focusable="False"
Grid.Column="3"
Height="{TemplateBinding TitleBarHeight}"
VerticalAlignment="Top"
x:Name="PART_RightWindowCommands" />
<!-- Window 按钮命令 -->
<ContentPresenter
Content="{TemplateBinding WindowButtons}"
Focusable="False"
Grid.Column="4"
Height="{TemplateBinding TitleBarHeight}"
VerticalAlignment="Top"
x:Name="PART_WindowButtons" />
<!-- 主窗口内容 -->
<ContentPresenter
Focusable="False"
Grid.ColumnSpan="5"
Grid.Row="1" />
<!-- ResizeGrip -->
<ResizeGrip
Grid.ColumnSpan="5"
Grid.Row="1"
HorizontalAlignment="Right"
IsTabStop="False"
UseLayoutRounding="True"
VerticalAlignment="Bottom"
Visibility="Collapsed"
x:Name="WindowResizeGrip" />
</Grid>
</AdornerDecorator>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="UseNoneWindowStyle" Value="True">
<Setter Property="Grid.RowSpan" TargetName="PART_TitleBarThumb" Value="2" />
</Trigger>
<Trigger Property="Icon" Value="{x:Null}">
<Setter Property="Visibility" TargetName="PART_Icon" Value="Collapsed" />
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IgnoreTaskbar" Value="False" />
<Condition Property="WindowState" Value="Maximized" />
</MultiTrigger.Conditions>
<Setter Property="Margin" TargetName="LayoutRoot" Value="7" />
</MultiTrigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="ResizeMode" Value="CanResizeWithGrip" />
<Condition Property="WindowState" Value="Normal" />
</MultiTrigger.Conditions>
<Setter Property="Visibility" TargetName="WindowResizeGrip" Value="Visible" />
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

View File

@@ -0,0 +1,9 @@
namespace AntDesignWPF.Controls
{
using System;
public class ClosingWindowEventHandlerArgs : EventArgs
{
public bool Cancelled { get; set; }
}
}

View File

@@ -0,0 +1,49 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:controls="clr-namespace:AntDesignWPF.Controls"
xmlns:helpers="clr-namespace:AntDesignWPF.Helpers"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- WindowButtons/WindowCommands -->
<Style TargetType="{x:Type ButtonBase}" x:Key="Ant.WindowButton">
<Setter Property="Padding" Value="12,0" />
<Setter Property="IsTabStop" Value="False" />
<Setter Property="Focusable" Value="False" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="helpers:AntControl.PressedBackground" Value="{DynamicResource AntDesign.Brush.BackgroundSpotlight}" />
<Setter Property="helpers:AntControl.MouseOverBackground" Value="{DynamicResource AntDesign.Brush.FillPrimary}" />
<Setter Property="Foreground" Value="{Binding TitleBarForeground, Mode=OneWay, RelativeSource={RelativeSource AncestorType={x:Type controls:AntWindow}}}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ButtonBase}">
<Grid Background="{TemplateBinding Background}" x:Name="Root">
<ContentPresenter
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
Margin="{TemplateBinding Padding}"
RecognizesAccessKey="True"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" TargetName="Root" Value="{Binding Path=(helpers:AntControl.MouseOverBackground), Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" TargetName="Root" Value="{Binding Path=(helpers:AntControl.PressedBackground), Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="{DynamicResource AntDesign.Brush.TextQuaternary}" />
</Trigger>
</Style.Triggers>
</Style>
</ResourceDictionary>

View File

@@ -0,0 +1,296 @@
using System.ComponentModel;
using System.Text;
using System.Windows.Threading;
using System.Windows.Controls.Primitives;
using AntDesignWPF.Win32;
using SystemCommands = System.Windows.SystemCommands;
namespace AntDesignWPF.Controls
{
[TemplatePart(Name = PART_Min, Type = typeof(ButtonBase))]
[TemplatePart(Name = PART_Max, Type = typeof(ButtonBase))]
[TemplatePart(Name = PART_Close, Type = typeof(ButtonBase))]
public class WindowButtons : ContentControl, INotifyPropertyChanged
{
#region Events
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void RaisePropertyChanged(string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public event ClosingWindowEventHandler ClosingWindow;
public delegate void ClosingWindowEventHandler(object sender, ClosingWindowEventHandlerArgs args);
#endregion
#region Fields
private const string PART_Min = "PART_Min";
private const string PART_Max = "PART_Max";
private const string PART_Close = "PART_Close";
private ButtonBase min;
private ButtonBase max;
private ButtonBase close;
private SafeLibraryHandle user32;
#endregion
#region Properties
public static readonly DependencyProperty MinimizeProperty =
DependencyProperty.Register("Minimize", typeof(string), typeof(WindowButtons), new PropertyMetadata(null));
/// <summary>
/// Gets or sets the minimize button tooltip.
/// </summary>
public string Minimize
{
get { return (string)GetValue(MinimizeProperty); }
set { SetValue(MinimizeProperty, value); }
}
public static readonly DependencyProperty MaximizeProperty =
DependencyProperty.Register("Maximize", typeof(string), typeof(WindowButtons), new PropertyMetadata(null));
/// <summary>
/// Gets or sets the maximize button tooltip.
/// </summary>
public string Maximize
{
get { return (string)GetValue(MaximizeProperty); }
set { SetValue(MaximizeProperty, value); }
}
public static readonly DependencyProperty RestoreProperty =
DependencyProperty.Register("Restore", typeof(string), typeof(WindowButtons), new PropertyMetadata(null));
/// <summary>
/// Gets or sets the restore button tooltip.
/// </summary>
public string Restore
{
get { return (string)GetValue(RestoreProperty); }
set { SetValue(RestoreProperty, value); }
}
public static readonly DependencyProperty CloseProperty =
DependencyProperty.Register("Close", typeof(string), typeof(WindowButtons), new PropertyMetadata(null));
/// <summary>
/// Gets or sets the close button tooltip.
/// </summary>
public string Close
{
get { return (string)GetValue(CloseProperty); }
set { SetValue(CloseProperty, value); }
}
public static readonly DependencyProperty MinimizeStyleProperty =
DependencyProperty.Register("MinimizeStyle", typeof(Style), typeof(WindowButtons), new PropertyMetadata(null, OnStyleChanged));
/// <summary>
/// Gets or sets the style for the minimize button.
/// </summary>
public Style MinimizeStyle
{
get { return (Style)GetValue(MinimizeStyleProperty); }
set { SetValue(MinimizeStyleProperty, value); }
}
public static readonly DependencyProperty MaximizeStyleProperty =
DependencyProperty.Register("MaximizeStyle", typeof(Style), typeof(WindowButtons), new PropertyMetadata(null, OnStyleChanged));
/// <summary>
/// Gets or sets the style for the maximize button.
/// </summary>
public Style MaximizeStyle
{
get { return (Style)GetValue(MaximizeStyleProperty); }
set { SetValue(MaximizeStyleProperty, value); }
}
public static readonly DependencyProperty CloseStyleProperty =
DependencyProperty.Register("CloseStyle", typeof(Style), typeof(WindowButtons), new PropertyMetadata(null, OnStyleChanged));
/// <summary>
/// Gets or sets the style for the close button.
/// </summary>
public Style CloseStyle
{
get { return (Style)GetValue(CloseStyleProperty); }
set { SetValue(CloseStyleProperty, value); }
}
private static void OnStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue == e.OldValue) return;
(d as WindowButtons).ApplyStyle();
}
private AntWindow parentWindow;
public AntWindow ParentWindow
{
get { return parentWindow; }
set
{
if (Equals(parentWindow, value))
{
return;
}
parentWindow = value;
RaisePropertyChanged("ParentWindow");
}
}
#endregion
#region Constructors
static WindowButtons()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(WindowButtons), new FrameworkPropertyMetadata(typeof(WindowButtons)));
}
public WindowButtons()
{
Dispatcher.BeginInvoke(DispatcherPriority.Loaded,
new Action(() =>
{
if (string.IsNullOrWhiteSpace(Minimize))
{
SetCurrentValue(MinimizeProperty, GetCaption(900));
}
if (string.IsNullOrWhiteSpace(Maximize))
{
SetCurrentValue(MaximizeProperty, GetCaption(901));
}
if (string.IsNullOrWhiteSpace(Close))
{
SetCurrentValue(CloseProperty, GetCaption(905));
}
if (string.IsNullOrWhiteSpace(Restore))
{
SetCurrentValue(RestoreProperty, GetCaption(903));
}
}));
}
private string GetCaption(int id)
{
if (user32 == null)
{
user32 = UnsafeNativeMethods.LoadLibrary(Environment.SystemDirectory + "\\User32.dll");
}
var sb = new StringBuilder(256);
UnsafeNativeMethods.LoadString(user32, (uint)id, sb, sb.Capacity);
return sb.ToString().Replace("&", "");
}
#endregion
#region Overrides
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
close = Template.FindName(PART_Close, this) as ButtonBase;
if (close != null)
{
close.Click += OnClose;
}
max = Template.FindName(PART_Max, this) as ButtonBase;
if (max != null)
{
max.Click += OnMaximize;
}
min = Template.FindName(PART_Min, this) as ButtonBase;
if (min != null)
{
min.Click += OnMinimize;
}
ApplyStyle();
}
#endregion
#region Methods
private void ApplyStyle()
{
if (min != null)
{
min.Style = MinimizeStyle;
}
if (max != null)
{
max.Style = MaximizeStyle;
}
if (close != null)
{
close.Style = CloseStyle;
}
}
#pragma warning disable 618
private void OnMinimize(object sender, RoutedEventArgs e)
{
if (ParentWindow != null)
{
SystemCommands.MinimizeWindow(ParentWindow);
}
}
private void OnMaximize(object sender, RoutedEventArgs e)
{
if (null == ParentWindow) return;
if (ParentWindow.WindowState == WindowState.Maximized)
{
SystemCommands.RestoreWindow(ParentWindow);
}
else
{
SystemCommands.MaximizeWindow(ParentWindow);
}
}
private void OnClose(object sender, RoutedEventArgs e)
{
var closingWindowEventHandlerArgs = new ClosingWindowEventHandlerArgs();
OnClosingWindow(closingWindowEventHandlerArgs);
if (closingWindowEventHandlerArgs.Cancelled) return;
ParentWindow?.Close();
}
protected void OnClosingWindow(ClosingWindowEventHandlerArgs args)
{
ClosingWindow?.Invoke(this, args);
}
#endregion
}
}

View File

@@ -0,0 +1,82 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:controls="clr-namespace:AntDesignWPF.Controls"
xmlns:helpers="clr-namespace:AntDesignWPF.Helpers"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/AntDesignWPF;component/Themes/Converters.xaml" />
<ResourceDictionary Source="pack://application:,,,/AntDesignWPF;component/Controls/AntWindow/WindowButton.xaml" />
</ResourceDictionary.MergedDictionaries>
<Style
BasedOn="{StaticResource Ant.WindowButton}"
TargetType="{x:Type Button}"
x:Key="Ant.WindowCloseButton">
<Setter Property="helpers:AntControl.MouseOverBackground" Value="{DynamicResource AntDesign.Brush.Error}" />
<Setter Property="helpers:AntControl.PressedBackground" Value="{Binding Path=(helpers:AntControl.MouseOverBackground), Mode=OneWay, ConverterParameter=7, RelativeSource={RelativeSource Self}, Converter={StaticResource ColorPaletteConverter}}" />
</Style>
<Style TargetType="{x:Type controls:WindowButtons}">
<Setter Property="IsTabStop" Value="False" />
<Setter Property="Focusable" Value="False" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="MinimizeStyle" Value="{StaticResource Ant.WindowButton}" />
<Setter Property="MaximizeStyle" Value="{StaticResource Ant.WindowButton}" />
<Setter Property="CloseStyle" Value="{StaticResource Ant.WindowCloseButton}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type controls:WindowButtons}">
<StackPanel Orientation="Horizontal">
<Button
ToolTip="{TemplateBinding Minimize}"
Visibility="{Binding ResizeMode, Mode=OneWay, RelativeSource={RelativeSource AncestorType={x:Type controls:AntWindow}}, Converter={StaticResource ResizeModeToVisibilityConverter}, ConverterParameter=MIN}"
x:Name="PART_Min">
<Path
Data="M0,1 L 12,1 12,1.8 0,1.8z"
Fill="{Binding Foreground, Mode=OneWay, RelativeSource={RelativeSource AncestorType={x:Type Button}}}"
RenderOptions.EdgeMode="Aliased" />
</Button>
<Button
ToolTip="{TemplateBinding Maximize}"
Visibility="{Binding ResizeMode, Mode=OneWay, RelativeSource={RelativeSource AncestorType={x:Type controls:AntWindow}}, Converter={StaticResource ResizeModeToVisibilityConverter}, ConverterParameter=MAX}"
x:Name="PART_Max">
<Path
Data="M0,0 L12,0 12,11 0,11z M1,1 L11,1 11,10.5 1,10.5z"
Fill="{Binding Foreground, Mode=OneWay, RelativeSource={RelativeSource AncestorType={x:Type Button}}}"
RenderOptions.EdgeMode="Aliased"
UseLayoutRounding="True"
x:Name="PART_MaxPath" />
</Button>
<Button
ToolTip="{TemplateBinding Close}"
UseLayoutRounding="True"
x:Name="PART_Close">
<Grid>
<Line
Stroke="{Binding Foreground, Mode=OneWay, RelativeSource={RelativeSource AncestorType={x:Type Button}}}"
X1="0"
X2="11"
Y1="0"
Y2="11" />
<Line
Stroke="{Binding Foreground, Mode=OneWay, RelativeSource={RelativeSource AncestorType={x:Type Button}}}"
X1="0"
X2="11"
Y1="11"
Y2="0" />
</Grid>
</Button>
</StackPanel>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding WindowState, RelativeSource={RelativeSource AncestorType={x:Type controls:AntWindow}}}" Value="Maximized">
<Setter Property="ToolTip" TargetName="PART_Max" Value="{Binding Restore, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" />
<Setter Property="Data" TargetName="PART_MaxPath" Value="M2,2 L2,0 12,0 12,10 10.5,10 10.5,9 11,9 11,1 2.5,1 2.5,2z M0,2 L10.5,2 10.5,11 0,11z M1,2.5 L10,2.5 10,10.5 1,10.5z" />
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

View File

@@ -0,0 +1,71 @@
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
namespace AntDesignWPF.Controls
{
public class WindowCommands : ItemsControl, INotifyPropertyChanged
{
#region Events
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void RaisePropertyChanged(string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
#region Properties
private AntWindow _parentWindow;
public AntWindow ParentWindow
{
get { return _parentWindow; }
set
{
if (Equals(_parentWindow, value))
{
return;
}
_parentWindow = value;
RaisePropertyChanged("ParentWindow");
}
}
public static readonly DependencyProperty SeparatorHeightProperty =
DependencyProperty.Register("SeparatorHeight", typeof(double), typeof(WindowCommands), new PropertyMetadata(double.NaN));
/// <summary>
/// Gets/sets the height of the separator.
/// </summary>
public double SeparatorHeight
{
get { return (double)GetValue(SeparatorHeightProperty); }
set { SetValue(SeparatorHeightProperty, value); }
}
#endregion
#region Constructors
static WindowCommands()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(WindowCommands), new FrameworkPropertyMetadata(typeof(WindowCommands)));
}
#endregion
}
public class WindowCommandsItem : AntContentControl
{
static WindowCommandsItem()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(WindowCommandsItem), new FrameworkPropertyMetadata(typeof(WindowCommandsItem)));
}
}
}

View File

@@ -0,0 +1,76 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:controls="clr-namespace:AntDesignWPF.Controls"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/AntDesignWPF;component/Themes/Converters.xaml" />
<ResourceDictionary Source="pack://application:,,,/AntDesignWPF;component/Controls/AntWindow/WindowButton.xaml" />
</ResourceDictionary.MergedDictionaries>
<Style TargetType="{x:Type controls:WindowCommands}">
<Setter Property="IsTabStop" Value="False" />
<Setter Property="Focusable" Value="False" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type controls:WindowCommands}">
<ControlTemplate.Resources>
<!-- Separator -->
<Style TargetType="Separator">
<Setter Property="Padding" Value="4,0" />
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Separator}">
<Rectangle
Fill="{Binding TitleBarForeground, Mode=OneWay, RelativeSource={RelativeSource AncestorType={x:Type controls:AntWindow}}}"
Height="{Binding SeparatorHeight, Mode=OneWay, RelativeSource={RelativeSource AncestorType={x:Type controls:WindowCommands}}}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
IsHitTestVisible="False"
Margin="{TemplateBinding Padding}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
UseLayoutRounding="True"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Width="1"
x:Name="Separator" />
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding SeparatorHeight, Mode=OneWay, RelativeSource={RelativeSource AncestorType={x:Type controls:WindowCommands}}}" Value="NaN">
<Setter Property="Height" TargetName="Separator" Value="{Binding TitleBarHeight, Mode=OneWay, ConverterParameter=2, RelativeSource={RelativeSource AncestorType={x:Type controls:AntWindow}}, Converter={StaticResource DivisionConverter}}" />
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- Buttons -->
<Style BasedOn="{StaticResource Ant.WindowButton}" TargetType="Button" />
<Style BasedOn="{StaticResource Ant.WindowButton}" TargetType="ToggleButton" />
</ControlTemplate.Resources>
<ItemsPresenter />
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type controls:WindowCommandsItem}">
<Setter Property="IsTabStop" Value="False" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type controls:WindowCommandsItem}">
<ContentPresenter />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>