Files
Future/Future.Contract/Behaviors/CustomTitleBar.cs
2025-08-30 17:19:57 +08:00

324 lines
15 KiB
C#

using Microsoft.Xaml.Behaviors;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shell;
using System.Windows;
using System.Windows.Shapes;
using System.Windows.Media.Animation;
using System.Windows.Input;
using System.Windows.Markup;
using System.ComponentModel;
namespace Future.Contract
{
/// <summary>
/// 为窗口提供自定义标题栏的行为
/// </summary>
[ContentProperty("ICON")]
public class CustomTitleBar : Behavior<Window>
{
//private readonly static string svgMax = "M959.72 0H294.216a63.96 63.96 0 0 0-63.96 63.96v127.92H64.28A63.96 63.96 0 0 0 0.32 255.84V959.4a63.96 63.96 0 0 0 63.96 63.96h703.56a63.96 63.96 0 0 0 63.96-63.96V792.465h127.92a63.96 63.96 0 0 0 63.96-63.96V63.96A63.96 63.96 0 0 0 959.72 0zM767.84 728.505V959.4H64.28V255.84h703.56z m189.322 0H831.8V255.84a63.96 63.96 0 0 0-63.96-63.96H294.216V63.96H959.72z";
//private readonly static string[] svgNomal = new string[] {
// "M785.960424 410.377773c0-14.634419-11.871277-26.608035-26.608035-26.608035L204.677194 383.769738c-14.634419 0-26.608035 11.871277-26.608035 26.608035l0 349.998001c0 14.634419 11.871277 26.608035 26.608035 26.608035l554.675195 0c14.634419 0 26.608035-11.871277 26.608035-26.608035L785.960424 410.377773zM740.931441 741.954827 223.098141 741.954827 223.098141 428.798721l517.8333 0L740.931441 741.954827z",
// "M856.471717 294.735159l-554.675195 0c-12.485309 0-22.514491 10.029182-22.514491 22.514491s10.029182 22.514491 22.514491 22.514491L838.153108 339.764142l0 331.679392c0 12.485309 10.029182 22.514491 22.514491 22.514491s22.514491-10.029182 22.514491-22.514491l0-349.998001C883.182091 306.708775 871.106136 294.735159 856.471717 294.735159z"
//};
//private readonly static Geometry svgMaxGeometry;
//private readonly static Geometry svgNomalGeometry;
//static CustomTitleBar()
//{
// svgMaxGeometry = Geometry.Parse(svgMax);
// GeometryGroup nomal = new GeometryGroup();
// nomal.Children.Add(Geometry.Parse(svgNomal[0]));
// nomal.Children.Add(Geometry.Parse(svgNomal[1]));
// svgNomalGeometry = nomal;
//}
private void AssociatedObject_Loaded(object sender, RoutedEventArgs e)
{
FrameworkElement winContent = this.AssociatedObject.Content as FrameworkElement;
if (winContent == null) return;
if (this.AssociatedObject.WindowState == WindowState.Maximized)
winContent.Margin = new Thickness(8);
else winContent.Margin = new Thickness(0);
Grid titleBarRoot = new Grid() { Height = this.TitleHeight };
titleBarRoot.Background = this.Background ?? this.AssociatedObject.Background;
StackPanel spLeft = new StackPanel() { VerticalAlignment = VerticalAlignment.Stretch, HorizontalAlignment = HorizontalAlignment.Left, Orientation = Orientation.Horizontal };
Border bIcon = new Border() { MinWidth = this.TitleHeight };
bIcon.Child = this.ICON ?? new Image() { Source = this.AssociatedObject.Icon };
TextBlock tbTitle = new TextBlock()
{
Text = this.AssociatedObject.Title,
VerticalAlignment = VerticalAlignment.Center,
HorizontalAlignment = HorizontalAlignment.Left,
Foreground = Foreground = this.Foreground ?? this.AssociatedObject.Foreground,
FontSize = this.FontSize
};
spLeft.Children.Add(bIcon);
spLeft.Children.Add(tbTitle);
string templateString = "" +
"<ResourceDictionary xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\r\n" +
" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\">\r\n" +
" <ControlTemplate x:Key=\"dpButtonTemplate\" TargetType=\"Button\">\r\n" +
" <Border BorderBrush=\"{TemplateBinding BorderBrush}\" Background=\"{TemplateBinding Background}\" BorderThickness=\"{TemplateBinding BorderThickness}\">\r\n" +
" <ContentPresenter Margin=\"{TemplateBinding Padding}\"/>\r\n" +
" </Border>\r\n" +
" </ControlTemplate>\r\n" +
"</ResourceDictionary>\r\n";
ResourceDictionary dictionary = (ResourceDictionary)XamlReader.Parse(templateString);
ControlTemplate template = (ControlTemplate)dictionary["dpButtonTemplate"] as ControlTemplate;
StackPanel spRight = new StackPanel() { VerticalAlignment = VerticalAlignment.Stretch, HorizontalAlignment = HorizontalAlignment.Right, Orientation = Orientation.Horizontal, Width = this.TitleHeight * 4, FlowDirection = FlowDirection.RightToLeft };
Button butClose = new Button()
{
Name = "Close",
Background = this.Background ?? this.AssociatedObject.Background,
Foreground = this.Foreground ?? this.AssociatedObject.Foreground,
BorderThickness = new Thickness(0),
Padding = new Thickness(this.TitleHeight * 0.2),
Template = template,
Content = new Viewbox()
{
Child = new Path()
{
Data = Geometry.Parse("M548.992 503.744L885.44 167.328a31.968 31.968 0 1 0-45.248-45.248L503.744 458.496 167.328 122.08a31.968 31.968 0 1 0-45.248 45.248l336.416 336.416L122.08 840.16a31.968 31.968 0 1 0 45.248 45.248l336.416-336.416L840.16 885.44a31.968 31.968 0 1 0 45.248-45.248L548.992 503.744z"),
Height = 1024,
Width = 1024,
Fill = this.AssociatedObject.Foreground
}
}
};
Button butMax = new Button()
{
Name = "Max",
Background = this.Background ?? this.AssociatedObject.Background,
Foreground = this.Foreground ?? this.AssociatedObject.Foreground,
BorderThickness = new Thickness(0),
Padding = new Thickness(this.TitleHeight*0.2+3),
Template = template,
Content = new Viewbox()
{
Child = new Path()
{
Data = Geometry.Parse("M959.72 0H294.216a63.96 63.96 0 0 0-63.96 63.96v127.92H64.28A63.96 63.96 0 0 0 0.32 255.84V959.4a63.96 63.96 0 0 0 63.96 63.96h703.56a63.96 63.96 0 0 0 63.96-63.96V792.465h127.92a63.96 63.96 0 0 0 63.96-63.96V63.96A63.96 63.96 0 0 0 959.72 0zM767.84 728.505V959.4H64.28V255.84h703.56z m189.322 0H831.8V255.84a63.96 63.96 0 0 0-63.96-63.96H294.216V63.96H959.72z"),
Height = 1024,
Width = 1024,
Fill = this.AssociatedObject.Foreground
}
}
};
Button butMin = new Button()
{
Name = "Min",
Background = this.Background ?? this.AssociatedObject.Background,
Foreground = this.Foreground ?? this.AssociatedObject.Foreground,
BorderThickness = new Thickness(0),
Padding = new Thickness(this.TitleHeight * 0.2),
Template = template,
Content = new Viewbox()
{
Child = new Path()
{
Data = Geometry.Parse("M130 545.3h766c17.7 0 32-14.3 32-32s-14.3-32-32-32H130c-17.7 0-32 14.3-32 32 0 17.6 14.3 32 32 32z"),
Height = 1024,
Width = 1024,
Fill = this.AssociatedObject.Foreground
}
}
};
butClose.Click += ButClose_Click;
butMax.Click += ButMax_Click;
butMin.Click += ButMin_Click;
spRight.Children.Add(butClose);
spRight.Children.Add(butMax);
spRight.Children.Add(butMin);
butClose.AddHandler(Button.MouseEnterEvent, new RoutedEventHandler(this.ButMouseEnter));
butMax.AddHandler(Button.MouseEnterEvent, new RoutedEventHandler(this.ButMouseEnter));
butMin.AddHandler(Button.MouseEnterEvent, new RoutedEventHandler(this.ButMouseEnter));
butClose.AddHandler(Button.MouseLeaveEvent, new RoutedEventHandler(this.ButMouseLeave));
butMax.AddHandler(Button.MouseLeaveEvent, new RoutedEventHandler(this.ButMouseLeave));
butMin.AddHandler(Button.MouseLeaveEvent, new RoutedEventHandler(this.ButMouseLeave));
titleBarRoot.Children.Add(spLeft);
titleBarRoot.Children.Add(spRight);
titleBarRoot.Children.Add(new TextBlock()
{
Text = this.Header,
VerticalAlignment = VerticalAlignment.Center,
HorizontalAlignment = HorizontalAlignment.Center,
Foreground = this.Foreground ?? this.AssociatedObject.Foreground,
FontSize = this.FontSize * 0.8,
Opacity = 0.5
});
WindowChrome.SetIsHitTestVisibleInChrome(spRight, true);
this.TitleBar.Child = titleBarRoot;
}
private void ButMouseEnter(object sender, RoutedEventArgs e)
{
var button = sender as Button;
if (button != null) button.Background = this.HoverBrush;
}
private void ButMouseLeave(object sender, RoutedEventArgs e)
{
var button = sender as Button;
if (button != null) button.Background = new SolidColorBrush(Colors.Transparent);
}
private void ButMin_Click(object sender, RoutedEventArgs e)
{
this.AssociatedObject.WindowState = WindowState.Minimized;
}
private void ButMax_Click(object sender, RoutedEventArgs e)
{
if (this.AssociatedObject.WindowState == WindowState.Maximized)
this.AssociatedObject.WindowState = WindowState.Normal;
else
this.AssociatedObject.WindowState = WindowState.Maximized;
}
private void ButClose_Click(object sender, RoutedEventArgs e)
{
this.AssociatedObject.Close();
}
protected override void OnAttached()
{
Window target = this.AssociatedObject;
WindowChrome.SetWindowChrome(target, new WindowChrome() { CaptionHeight = this.TitleHeight });
this.AssociatedObject.Loaded += AssociatedObject_Loaded;
this.AssociatedObject.StateChanged += AssociatedObject_StateChanged;
}
private void AssociatedObject_StateChanged(object sender, EventArgs e)
{
var winContent = this.AssociatedObject.Content as FrameworkElement;
if (winContent == null) return;
if (this.AssociatedObject.WindowState == WindowState.Maximized)
winContent.Margin = new Thickness(8);
else winContent.Margin = new Thickness(0);
}
protected override void OnDetaching()
{
this.AssociatedObject.Loaded -= AssociatedObject_Loaded;
}
public int TitleHeight
{
get { return (int)GetValue(TitleHeightProperty); }
set { SetValue(TitleHeightProperty, value); }
}
// Using a DependencyProperty as the backing store for TitleHeight. This enables animation, styling, binding, etc...
public static readonly DependencyProperty TitleHeightProperty =
DependencyProperty.Register("TitleHeight", typeof(int), typeof(CustomTitleBar), new PropertyMetadata(40));
public Decorator TitleBar
{
get { return (Decorator)GetValue(TitleBarProperty); }
set { SetValue(TitleBarProperty, value); }
}
// Using a DependencyProperty as the backing store for TitleBar. This enables animation, styling, binding, etc...
public static readonly DependencyProperty TitleBarProperty =
DependencyProperty.Register("TitleBar", typeof(Decorator), typeof(CustomTitleBar), new PropertyMetadata(null));
public Brush Background
{
get { return (Brush)GetValue(BackgroundProperty); }
set { SetValue(BackgroundProperty, value); }
}
// Using a DependencyProperty as the backing store for Background. This enables animation, styling, binding, etc...
public static readonly DependencyProperty BackgroundProperty =
DependencyProperty.Register("Background", typeof(Brush), typeof(CustomTitleBar), new PropertyMetadata(null));
public Brush HoverBrush
{
get { return (Brush)GetValue(HoverBrushProperty); }
set { SetValue(HoverBrushProperty, value); }
}
// Using a DependencyProperty as the backing store for HoverBrush. This enables animation, styling, binding, etc...
public static readonly DependencyProperty HoverBrushProperty =
DependencyProperty.Register("HoverBrush", typeof(Brush), typeof(CustomTitleBar), new PropertyMetadata(null));
public Brush Foreground
{
get { return (Brush)GetValue(ForegroundProperty); }
set { SetValue(ForegroundProperty, value); }
}
// Using a DependencyProperty as the backing store for Foreground. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ForegroundProperty =
DependencyProperty.Register("Foreground", typeof(Brush), typeof(CustomTitleBar), new PropertyMetadata(null));
public UIElement ICON
{
get { return (UIElement)GetValue(ICONProperty); }
set { SetValue(ICONProperty, value); }
}
// Using a DependencyProperty as the backing store for ICON. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ICONProperty =
DependencyProperty.Register("ICON", typeof(UIElement), typeof(CustomTitleBar), new PropertyMetadata(null));
public double FontSize
{
get { return (double)GetValue(FontSizeProperty); }
set { SetValue(FontSizeProperty, value); }
}
// Using a DependencyProperty as the backing store for FontSize. This enables animation, styling, binding, etc...
public static readonly DependencyProperty FontSizeProperty =
DependencyProperty.Register("FontSize", typeof(double), typeof(CustomTitleBar), new PropertyMetadata(18.0));
public string Header
{
get { return (string)GetValue(HeaderProperty); }
set { SetValue(HeaderProperty, value); }
}
// Using a DependencyProperty as the backing store for Header. This enables animation, styling, binding, etc...
public static readonly DependencyProperty HeaderProperty =
DependencyProperty.Register("Header", typeof(string), typeof(CustomTitleBar), new PropertyMetadata(""));
}
}