diff --git a/Example/App.xaml b/Example/App.xaml new file mode 100644 index 0000000..423c29f --- /dev/null +++ b/Example/App.xaml @@ -0,0 +1,9 @@ + + + + + diff --git a/Example/App.xaml.cs b/Example/App.xaml.cs new file mode 100644 index 0000000..df2669e --- /dev/null +++ b/Example/App.xaml.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using System.Windows; + +namespace Example +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + } +} diff --git a/Example/AssemblyInfo.cs b/Example/AssemblyInfo.cs new file mode 100644 index 0000000..8b5504e --- /dev/null +++ b/Example/AssemblyInfo.cs @@ -0,0 +1,10 @@ +using System.Windows; + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] diff --git a/Example/Custom4Behavior.xaml b/Example/Custom4Behavior.xaml new file mode 100644 index 0000000..e8c95e0 --- /dev/null +++ b/Example/Custom4Behavior.xaml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + diff --git a/Example/Custom4Behavior.xaml.cs b/Example/Custom4Behavior.xaml.cs new file mode 100644 index 0000000..3343dfe --- /dev/null +++ b/Example/Custom4Behavior.xaml.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Shapes; + +namespace Example +{ + /// + /// Custom4Behavior.xaml 的交互逻辑 + /// + public partial class Custom4Behavior : Window + { + public Custom4Behavior() + { + InitializeComponent(); + } + } +} diff --git a/Example/CustomWindow.xaml b/Example/CustomWindow.xaml new file mode 100644 index 0000000..0aff57a --- /dev/null +++ b/Example/CustomWindow.xaml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Example/CustomWindow.xaml.cs b/Example/CustomWindow.xaml.cs new file mode 100644 index 0000000..43cca5c --- /dev/null +++ b/Example/CustomWindow.xaml.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Shapes; + +namespace Example +{ + /// + /// CustomWindow.xaml 的交互逻辑 + /// + public partial class CustomWindow : Window + { + public CustomWindow() + { + InitializeComponent(); + } + } +} diff --git a/Example/CustomWindowTitleBar.cs b/Example/CustomWindowTitleBar.cs new file mode 100644 index 0000000..07c3fa3 --- /dev/null +++ b/Example/CustomWindowTitleBar.cs @@ -0,0 +1,318 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Markup; +using System.Windows.Media; +using System.Windows.Shell; +using Microsoft.Xaml.Behaviors; +using System.Windows.Shapes; +using System.Windows.Media.Animation; +using System.Windows.Input; + +namespace Example +{ + /// + /// 为窗口提供自定义标题栏的行为 + /// + public class CustomTitleBar : Behavior + { + //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) + { + 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() { Width = this.TitleHeight }; + bIcon.Child = this.TitleIcon ?? new Image() { Source = this.AssociatedObject.Icon }; + TextBlock tbTitle = new TextBlock() + { + Text = this.Title, + VerticalAlignment = VerticalAlignment.Center, + HorizontalAlignment = HorizontalAlignment.Left, + Foreground = Foreground = this.Foreground ?? this.AssociatedObject.Foreground, + FontSize = this.AssociatedObject.FontSize + }; + + spLeft.Children.Add(bIcon); + spLeft.Children.Add(tbTitle); + + string templateString = "" + + "\r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + "\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(10), + 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(10), + 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(10), + 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 + }); + + WindowChrome.SetIsHitTestVisibleInChrome(spRight, true); + this.TitleBar.Child = titleBarRoot; + } + + private void ButMouseEnter(object sender, RoutedEventArgs e) + { + Button? button = sender as Button; + if (button != null) button.Background = this.HoverBrush; + } + + private void ButMouseLeave(object sender, RoutedEventArgs e) + { + Button? 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) + { + 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); + } + + 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 TitleIcon + { + get { return (UIElement)GetValue(TitleIconProperty); } + set { SetValue(TitleIconProperty, value); } + } + + // Using a DependencyProperty as the backing store for TitleIcon. This enables animation, styling, binding, etc... + public static readonly DependencyProperty TitleIconProperty = + DependencyProperty.Register("TitleIcon", typeof(UIElement), typeof(CustomTitleBar), new PropertyMetadata(null)); + + + + public string Title + { + get { return (string)GetValue(TitleProperty); } + set { SetValue(TitleProperty, value); } + } + + // Using a DependencyProperty as the backing store for Title. This enables animation, styling, binding, etc... + public static readonly DependencyProperty TitleProperty = + DependencyProperty.Register("Title", typeof(string), typeof(CustomTitleBar), new PropertyMetadata("")); + + + + 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("")); + + + } +} diff --git a/Example/Example.csproj b/Example/Example.csproj new file mode 100644 index 0000000..7f6360f --- /dev/null +++ b/Example/Example.csproj @@ -0,0 +1,11 @@ + + + WinExe + net6.0-windows7.0 + enable + true + + + + + \ No newline at end of file diff --git a/Example/MainWindow.xaml b/Example/MainWindow.xaml new file mode 100644 index 0000000..2a72ae6 --- /dev/null +++ b/Example/MainWindow.xaml @@ -0,0 +1,18 @@ + + +