准备编写「WindowBorder」控件
This commit is contained in:
@@ -58,4 +58,17 @@
|
|||||||
</Setter.Value>
|
</Setter.Value>
|
||||||
</Setter>
|
</Setter>
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
|
<Style TargetType="{x:Type local:WindowBorder}">
|
||||||
|
<Setter Property="Template">
|
||||||
|
<Setter.Value>
|
||||||
|
<ControlTemplate TargetType="{x:Type local:WindowBorder}">
|
||||||
|
<Border Background="{TemplateBinding Background}"
|
||||||
|
BorderBrush="{TemplateBinding BorderBrush}"
|
||||||
|
BorderThickness="{TemplateBinding BorderThickness}">
|
||||||
|
</Border>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
|
|||||||
258
DeedyDesigner/Deedy.Wpf/WindowBorder.cs
Normal file
258
DeedyDesigner/Deedy.Wpf/WindowBorder.cs
Normal file
@@ -0,0 +1,258 @@
|
|||||||
|
using System.ComponentModel;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using System.Windows.Markup;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using Shell = System.Windows.Shell;
|
||||||
|
|
||||||
|
namespace Deedy
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 为自定义窗口提供标题栏与内容容器;可以作为一个窗口的直接子节点
|
||||||
|
/// </summary>
|
||||||
|
[ContentProperty("Content")]
|
||||||
|
[TemplatePart(Name = "MainMenu", Type = typeof(Menu))]
|
||||||
|
[TemplatePart(Name = "Minimize", Type = typeof(Button))]
|
||||||
|
[TemplatePart(Name = "Maximize", Type = typeof(Button))]
|
||||||
|
[TemplatePart(Name = "CloseWin", Type = typeof(Button))]
|
||||||
|
[TemplatePart(Name = "TitleBar", Type = typeof(Control))]
|
||||||
|
[TemplatePart(Name = "Controller", Type = typeof(Panel))]
|
||||||
|
[TemplatePart(Name = "Container", Type = typeof(Decorator))]
|
||||||
|
public class WindowBorder : HeaderedContentControl
|
||||||
|
{
|
||||||
|
static WindowBorder()
|
||||||
|
{
|
||||||
|
DefaultStyleKeyProperty.OverrideMetadata(typeof(WindowBorder), new FrameworkPropertyMetadata(typeof(WindowBorder)));
|
||||||
|
BackgroundProperty.OverrideMetadata(typeof(WindowBorder), new FrameworkPropertyMetadata(Brushes.Gray));
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 悬停画刷
|
||||||
|
/// </summary>
|
||||||
|
public Brush HoverBrush
|
||||||
|
{
|
||||||
|
get { return (Brush)GetValue(HoverBrushProperty); }
|
||||||
|
set { SetValue(HoverBrushProperty, value); }
|
||||||
|
}
|
||||||
|
public static readonly DependencyProperty HoverBrushProperty =
|
||||||
|
DependencyProperty.Register("HoverBrush", typeof(Brush), typeof(WindowBorder), new PropertyMetadata(Brushes.Silver));
|
||||||
|
/// <summary>
|
||||||
|
/// 标题画刷
|
||||||
|
/// </summary>
|
||||||
|
public Brush Headground
|
||||||
|
{
|
||||||
|
get { return (Brush)GetValue(HeadgroundProperty); }
|
||||||
|
set { SetValue(HeadgroundProperty, value); }
|
||||||
|
}
|
||||||
|
public static readonly DependencyProperty HeadgroundProperty =
|
||||||
|
DependencyProperty.Register("Headground", typeof(Brush), typeof(WindowBorder), new PropertyMetadata(Brushes.DimGray));
|
||||||
|
/// <summary>
|
||||||
|
/// 标题高度
|
||||||
|
/// </summary>
|
||||||
|
public double HeaderHeight
|
||||||
|
{
|
||||||
|
get { return (double)GetValue(HeaderHeightProperty); }
|
||||||
|
set { SetValue(HeaderHeightProperty, value); }
|
||||||
|
}
|
||||||
|
public static readonly DependencyProperty HeaderHeightProperty =
|
||||||
|
DependencyProperty.Register("HeaderHeight", typeof(double), typeof(WindowBorder), new PropertyMetadata(40.0,
|
||||||
|
(d, e) => (d as WindowBorder)?.HeaderHeight_PropertyChangedCallback(e)));
|
||||||
|
/// <summary>
|
||||||
|
/// 处理「WindowBorder.HeaderHeight」属性变更
|
||||||
|
/// </summary>
|
||||||
|
protected virtual void HeaderHeight_PropertyChangedCallback(DependencyPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if ((double)e.NewValue < 32) this.HeaderHeight = 32;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 菜单
|
||||||
|
/// </summary>
|
||||||
|
public MenuItem Menu
|
||||||
|
{
|
||||||
|
get { return (MenuItem)GetValue(MenuProperty); }
|
||||||
|
set { SetValue(MenuProperty, value); }
|
||||||
|
}
|
||||||
|
public static readonly DependencyProperty MenuProperty =
|
||||||
|
DependencyProperty.Register("Menu", typeof(MenuItem), typeof(WindowBorder), new PropertyMetadata(null,
|
||||||
|
(d, e) => (d as WindowBorder)?.Menu_PropertyChangedCallback(e)));
|
||||||
|
/// <summary>
|
||||||
|
/// 处理「WindowBorder.Menu」属性变更
|
||||||
|
/// </summary>
|
||||||
|
protected virtual void Menu_PropertyChangedCallback(DependencyPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (this.MainMenu != null)
|
||||||
|
{
|
||||||
|
this.MainMenu.Items.Clear();
|
||||||
|
if (e.NewValue is MenuItem menu)
|
||||||
|
{
|
||||||
|
menu.Height = this.HeaderHeight;
|
||||||
|
menu.Background = Brushes.Transparent;
|
||||||
|
this.MainMenu.Items.Add(menu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Panel? Controller;
|
||||||
|
private Decorator? Container;
|
||||||
|
private Button? Minimize;
|
||||||
|
private Button? Maximize;
|
||||||
|
private Button? CloseWin;
|
||||||
|
private Menu? MainMenu;
|
||||||
|
private Control? TitleBar;
|
||||||
|
|
||||||
|
private Window? Target;
|
||||||
|
private Shell.WindowChrome? Chrome;
|
||||||
|
|
||||||
|
private static bool IsNeedOverrideMetadata = true;
|
||||||
|
public WindowBorder() { }
|
||||||
|
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.TitleBar = GetTemplateChild("TitleBar") as Control;
|
||||||
|
this.MainMenu = GetTemplateChild("MainMenu") as Menu;
|
||||||
|
|
||||||
|
if (this.MainMenu != null)
|
||||||
|
{
|
||||||
|
this.MainMenu.Items.Clear();
|
||||||
|
if (this.Menu != null)
|
||||||
|
{
|
||||||
|
this.Menu.Height = this.Height;
|
||||||
|
this.Menu.Background = Brushes.Transparent;
|
||||||
|
this.MainMenu.Items.Add(this.Menu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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 Shell.WindowChrome() { CaptionHeight = this.HeaderHeight };
|
||||||
|
Shell.WindowChrome.SetWindowChrome(this.Target, this.Chrome);
|
||||||
|
Shell.WindowChrome.SetIsHitTestVisibleInChrome(this.Container, true);
|
||||||
|
Shell.WindowChrome.SetIsHitTestVisibleInChrome(this.Controller, true);
|
||||||
|
|
||||||
|
if (this.Controller != null)
|
||||||
|
{
|
||||||
|
foreach (var c in this.Controller.Children)
|
||||||
|
{
|
||||||
|
if (c is Button button) button.AddHandler(Button.ClickEvent, new RoutedEventHandler(this.CommandButton_Click));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.Menu != null) this.Menu.Height = this.HeaderHeight;
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
this.Visibility = Visibility.Visible;
|
||||||
|
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.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.TitleBar != null) this.TitleBar.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,6 +8,9 @@ using Shell = System.Windows.Shell;
|
|||||||
|
|
||||||
namespace Deedy
|
namespace Deedy
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 为自定义窗口提供标题栏
|
||||||
|
/// </summary>
|
||||||
[ContentProperty("Header")]
|
[ContentProperty("Header")]
|
||||||
[TemplatePart(Name = "MainMenu", Type = typeof(Menu))]
|
[TemplatePart(Name = "MainMenu", Type = typeof(Menu))]
|
||||||
[TemplatePart(Name = "Minimize", Type = typeof(Button))]
|
[TemplatePart(Name = "Minimize", Type = typeof(Button))]
|
||||||
|
|||||||
Reference in New Issue
Block a user