diff --git a/DeedyDesigner/Deedy.Testing/Deedy.Testing.csproj b/DeedyDesigner/Deedy.Testing/Deedy.Testing.csproj index 67588fb..127a1f1 100644 --- a/DeedyDesigner/Deedy.Testing/Deedy.Testing.csproj +++ b/DeedyDesigner/Deedy.Testing/Deedy.Testing.csproj @@ -10,6 +10,7 @@ + diff --git a/DeedyDesigner/Deedy.Testing/MainWindow.xaml b/DeedyDesigner/Deedy.Testing/MainWindow.xaml index f63d84b..17cb653 100644 --- a/DeedyDesigner/Deedy.Testing/MainWindow.xaml +++ b/DeedyDesigner/Deedy.Testing/MainWindow.xaml @@ -18,6 +18,7 @@ + + + + + + + + + + diff --git a/DeedyDesigner/Deedy.Wpf/WindowHeader.cs b/DeedyDesigner/Deedy.Wpf/WindowHeader.cs new file mode 100644 index 0000000..46f21de --- /dev/null +++ b/DeedyDesigner/Deedy.Wpf/WindowHeader.cs @@ -0,0 +1,214 @@ +using System.ComponentModel; +using System.Text; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Markup; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; +using System.Windows.Shell; + +namespace Deedy +{ + [ContentProperty("Child")] + [TemplatePart(Name = "IconView", Type = typeof(Border))] + [TemplatePart(Name = "TitleBar", Type = typeof(TextBlock))] + [TemplatePart(Name = "Minimize", Type = typeof(Button))] + [TemplatePart(Name = "Maximize", Type = typeof(Button))] + [TemplatePart(Name = "CloseWin", Type = typeof(Button))] + [TemplatePart(Name = "Controller", Type = typeof(Panel))] + [TemplatePart(Name = "Container", Type = typeof(Decorator))] + public class WindowHeader : Control + { + static WindowHeader() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(WindowHeader), new FrameworkPropertyMetadata(typeof(WindowHeader))); + BackgroundProperty.OverrideMetadata(typeof(WindowHeader), new FrameworkPropertyMetadata(Brushes.DimGray)); + } + public Brush HoverBrush + { + get { return (Brush)GetValue(HoverBrushProperty); } + set { SetValue(HoverBrushProperty, value); } + } + + public static readonly DependencyProperty HoverBrushProperty = + DependencyProperty.Register("HoverBrush", typeof(Brush), typeof(WindowHeader), new PropertyMetadata(Brushes.Silver)); + + public UIElement Child + { + get { return (UIElement)GetValue(ChildProperty); } + set { SetValue(ChildProperty, value); } + } + + public static readonly DependencyProperty ChildProperty = + DependencyProperty.Register("Child", typeof(UIElement), typeof(WindowHeader), new PropertyMetadata(null, (d, e) => + { + WindowHeader windowHeader = (WindowHeader)d; + if (e.NewValue != null) + { + if (windowHeader.Container != null) + windowHeader.Container.Child = e.NewValue as UIElement; + } + })); + + private Panel? Controller; + private Decorator? Container; + private Button? Minimize; + private Button? Maximize; + private Button? CloseWin; + private TextBlock? TitleBar; + private Border? IconView; + + private Window? Target; + private WindowChrome? Chrome; + + private static bool IsNeedOverrideMetadata = true; + public WindowHeader() { } + public void OnAttached() + { + FrameworkElement? parent = this.Parent as FrameworkElement; + Window? target = parent as Window; + while (parent != null && target == null) + { + parent = parent.Parent as FrameworkElement; + target = parent as Window; + } + //这是第【1】步 + if (target == null && !DesignerProperties.GetIsInDesignMode(this)) throw new ArgumentNullException("窗体装饰器[WindowDecorator]对象不可以附加到一个空的Window对象上!"); + this.Target = target; + if (this.Target == null) return; + this.Target.StateChanged += Target_StateChanged; + this.Target.Loaded += Target_Loaded; + if (IsNeedOverrideMetadata) + { + Window.WindowStyleProperty.OverrideMetadata(this.Target.GetType(), new FrameworkPropertyMetadata((d, e) => this.AdjustVisual())); + Window.ResizeModeProperty.OverrideMetadata(this.Target.GetType(), new FrameworkPropertyMetadata((d, e) => this.AdjustVisual())); + IsNeedOverrideMetadata = false; + } + } + public override void OnApplyTemplate() + { + this.OnDetaching(); + base.OnApplyTemplate(); + this.OnAttached(); + //这是第【2】步 + this.Controller = GetTemplateChild("Controller") as Panel; + this.Container = GetTemplateChild("Container") as Decorator; + this.Minimize = GetTemplateChild("Minimize") as Button; + this.Maximize = GetTemplateChild("Maximize") as Button; + this.CloseWin = GetTemplateChild("CloseWin") as Button; + this.IconView = GetTemplateChild("IconView") as Border; + this.TitleBar = GetTemplateChild("TitleBar") as TextBlock; + if (this.Container != null) this.Container.Child = this.Child; + } + private void Target_Loaded(object sender, RoutedEventArgs e) + { + if (this.Background == BackgroundProperty.DefaultMetadata.DefaultValue) this.SetBinding(BackgroundProperty, new Binding() { Source = this.Target, Path = new PropertyPath(BackgroundProperty.Name) }); + if (this.BorderBrush == BorderBrushProperty.DefaultMetadata.DefaultValue) this.SetBinding(BorderBrushProperty, new Binding() { Source = this.Target, Path = new PropertyPath(BorderBrushProperty.Name) }); + //这是第【3】步 + this.Chrome = new WindowChrome() { CaptionHeight = this.ActualHeight }; + WindowChrome.SetWindowChrome(this.Target, this.Chrome); + WindowChrome.SetIsHitTestVisibleInChrome(this.Container, true); + WindowChrome.SetIsHitTestVisibleInChrome(this.Controller, true); + if (this.Controller != null) + { + foreach (var c in this.Controller.Children) + { + Button? button = c as Button; + button?.AddHandler(Button.ClickEvent, new RoutedEventHandler(this.CommandButton_Click)); + button?.AddHandler(Button.MouseEnterEvent, new RoutedEventHandler((s, e) => ((Button)e.Source).Background = this.HoverBrush)); + button?.AddHandler(Button.MouseLeaveEvent, new RoutedEventHandler((s, e) => ((Button)e.Source).Background = Brushes.Transparent)); + } + } + this.AdjustVisual(); + this.AdjustMargin(); + } + public void OnDetaching() + { + if (this.Target != null) + { + this.Target.StateChanged -= this.Target_StateChanged; + this.Target.Loaded -= this.Target_Loaded; + } + } + private void AdjustVisual() + { + if (this.Target != null) + { + if (this.Controller != null) this.Controller.Visibility = Visibility.Visible; + if (this.Minimize != null) this.Minimize.Visibility = Visibility.Visible; + if (this.Maximize != null) this.Maximize.Visibility = Visibility.Visible; + if (this.CloseWin != null) this.CloseWin.Visibility = Visibility.Visible; + if (this.IconView != null) this.IconView.Visibility = Visibility.Visible; + if (this.TitleBar != null) this.TitleBar.Visibility = Visibility.Visible; + + if (this.Target.ResizeMode == ResizeMode.NoResize) + { + if (this.Minimize != null) this.Minimize.Visibility = Visibility.Collapsed; + if (this.Maximize != null) this.Maximize.Visibility = Visibility.Collapsed; + } + if (this.Target.ResizeMode == ResizeMode.CanMinimize) + { + if (this.Maximize != null) this.Maximize.Visibility = Visibility.Collapsed; + } + if (this.Target.WindowStyle == WindowStyle.None) + { + if (this.IconView != null) this.IconView.Visibility = Visibility.Collapsed; + if (this.TitleBar != null) this.TitleBar.Visibility = Visibility.Collapsed; + if (this.Controller != null) this.Controller.Visibility = Visibility.Collapsed; + } + if (this.Target.WindowStyle == WindowStyle.ToolWindow) + { + if (this.Controller != null) this.Controller.Visibility = Visibility.Collapsed; + } + } + } + private void AdjustMargin() + { + if (this.Target != null) + { + var winContent = this.Target.Content as FrameworkElement; + if (winContent == null) return; + if (this.Target.WindowState == WindowState.Maximized) + winContent.Margin = new Thickness(8); + else winContent.Margin = new Thickness(0); + } + } + private void Target_StateChanged(object? sender, EventArgs e) + { + this.AdjustMargin(); + } + private void CommandButton_Click(object sender, RoutedEventArgs e) + { + Button? button = sender as Button; + if (button != null) + { + switch (button.Name) + { + case "Minimize": + if (this.Target != null) this.Target.WindowState = WindowState.Minimized; + break; + case "Maximize": + { + if (this.Target != null) + { + if (this.Target.WindowState == WindowState.Maximized || this.Target.WindowState == WindowState.Minimized) + this.Target.WindowState = WindowState.Normal; + else this.Target.WindowState = WindowState.Maximized; + } + } + break; + case "CloseWin": + this.Target?.Close(); + break; + default: + break; + } + } + } + } +} \ No newline at end of file diff --git a/DeedyDesigner/DeedyDesigner.sln b/DeedyDesigner/DeedyDesigner.sln index 4e58c9e..fd12f9a 100644 --- a/DeedyDesigner/DeedyDesigner.sln +++ b/DeedyDesigner/DeedyDesigner.sln @@ -7,6 +7,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Deedy.Activity", "Deedy.Act EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Deedy.Testing", "Deedy.Testing\Deedy.Testing.csproj", "{550109E5-E39E-497A-84EB-08B075C6E766}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Deedy.Wpf", "Deedy.Wpf\Deedy.Wpf.csproj", "{C250C7CB-276E-4A50-9B79-5CC866274265}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -21,6 +23,10 @@ Global {550109E5-E39E-497A-84EB-08B075C6E766}.Debug|Any CPU.Build.0 = Debug|Any CPU {550109E5-E39E-497A-84EB-08B075C6E766}.Release|Any CPU.ActiveCfg = Release|Any CPU {550109E5-E39E-497A-84EB-08B075C6E766}.Release|Any CPU.Build.0 = Release|Any CPU + {C250C7CB-276E-4A50-9B79-5CC866274265}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C250C7CB-276E-4A50-9B79-5CC866274265}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C250C7CB-276E-4A50-9B79-5CC866274265}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C250C7CB-276E-4A50-9B79-5CC866274265}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE