diff --git a/DeedyDesigner/Deedy.Testing/MainWindow.xaml b/DeedyDesigner/Deedy.Testing/MainWindow.xaml index 5940972..f63d84b 100644 --- a/DeedyDesigner/Deedy.Testing/MainWindow.xaml +++ b/DeedyDesigner/Deedy.Testing/MainWindow.xaml @@ -15,7 +15,10 @@ - + + + + + + + + + diff --git a/DeedyDesigner/Deedy.Testing/WindowAdorner.cs b/DeedyDesigner/Deedy.Testing/WindowAdorner.cs new file mode 100644 index 0000000..db11aa6 --- /dev/null +++ b/DeedyDesigner/Deedy.Testing/WindowAdorner.cs @@ -0,0 +1,250 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +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.Markup; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; +using System.Windows.Shell; + +namespace Deedy +{ + /// + /// 按照步骤 1a 或 1b 操作,然后执行步骤 2 以在 XAML 文件中使用此自定义控件。 + /// + /// 步骤 1a) 在当前项目中存在的 XAML 文件中使用该自定义控件。 + /// 将此 XmlNamespace 特性添加到要使用该特性的标记文件的根 + /// 元素中: + /// + /// xmlns:MyNamespace="clr-namespace:Deedy.Testing" + /// + /// + /// 步骤 1b) 在其他项目中存在的 XAML 文件中使用该自定义控件。 + /// 将此 XmlNamespace 特性添加到要使用该特性的标记文件的根 + /// 元素中: + /// + /// xmlns:MyNamespace="clr-namespace:Deedy.Testing;assembly=Deedy.Testing" + /// + /// 您还需要添加一个从 XAML 文件所在的项目到此项目的项目引用, + /// 并重新生成以避免编译错误: + /// + /// 在解决方案资源管理器中右击目标项目,然后依次单击 + /// “添加引用”->“项目”->[浏览查找并选择此项目] + /// + /// + /// 步骤 2) + /// 继续操作并在 XAML 文件中使用控件。 + /// + /// + /// + /// + [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 WindowAdorner : Control + { + static WindowAdorner() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(WindowAdorner), new FrameworkPropertyMetadata(typeof(WindowAdorner))); + } + public Brush HoverBrush + { + get { return (Brush)GetValue(HoverBrushProperty); } + set { SetValue(HoverBrushProperty, value); } + } + + public static readonly DependencyProperty HoverBrushProperty = + DependencyProperty.Register("HoverBrush", typeof(Brush), typeof(WindowAdorner), 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(WindowAdorner), new PropertyMetadata(null, (d, e) => + { + WindowAdorner windowDecorator = (WindowAdorner)d; + if (e.NewValue != null) + { + if (windowDecorator.Container != null) + windowDecorator.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 Decorator? Decorator; + + private static bool IsNeedOverrideMetadata = true; + public WindowAdorner() { } + 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对象上!"); + //if (decorator == null) throw new ArgumentNullException("窗体装饰器[WindowDecorator]对象需要一个用于放置的容器!"); + this.Target = target; + //this.Decorator = decorator; + //this.Decorator.Child = this; + 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.Container != null) this.Container.Child = this.Child; + 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; + default: + this.Target?.Close(); + break; + } + } + } + } +} diff --git a/DeedyDesigner/Deedy.Testing/WindowAdornerTest.xaml b/DeedyDesigner/Deedy.Testing/WindowAdornerTest.xaml new file mode 100644 index 0000000..6f6860e --- /dev/null +++ b/DeedyDesigner/Deedy.Testing/WindowAdornerTest.xaml @@ -0,0 +1,16 @@ + + + +