月更
This commit is contained in:
717
AntDesignWPF/Controls/AntWindow/AntWindow.cs
Normal file
717
AntDesignWPF/Controls/AntWindow/AntWindow.cs
Normal 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
|
||||
}
|
||||
}
|
||||
202
AntDesignWPF/Controls/AntWindow/AntWindow.xaml
Normal file
202
AntDesignWPF/Controls/AntWindow/AntWindow.xaml
Normal 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>
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace AntDesignWPF.Controls
|
||||
{
|
||||
using System;
|
||||
|
||||
public class ClosingWindowEventHandlerArgs : EventArgs
|
||||
{
|
||||
public bool Cancelled { get; set; }
|
||||
}
|
||||
}
|
||||
49
AntDesignWPF/Controls/AntWindow/WindowButton.xaml
Normal file
49
AntDesignWPF/Controls/AntWindow/WindowButton.xaml
Normal 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>
|
||||
296
AntDesignWPF/Controls/AntWindow/WindowButtons.cs
Normal file
296
AntDesignWPF/Controls/AntWindow/WindowButtons.cs
Normal 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
|
||||
}
|
||||
}
|
||||
82
AntDesignWPF/Controls/AntWindow/WindowButtons.xaml
Normal file
82
AntDesignWPF/Controls/AntWindow/WindowButtons.xaml
Normal 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>
|
||||
71
AntDesignWPF/Controls/AntWindow/WindowCommands.cs
Normal file
71
AntDesignWPF/Controls/AntWindow/WindowCommands.cs
Normal 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)));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
76
AntDesignWPF/Controls/AntWindow/WindowCommands.xaml
Normal file
76
AntDesignWPF/Controls/AntWindow/WindowCommands.xaml
Normal 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>
|
||||
Reference in New Issue
Block a user