【发布时间】:2011-10-11 03:50:10
【问题描述】:
如何为 WPF 窗口创建一个基本的自定义窗口镶边,它不包括关闭按钮,但仍然是一个可移动和可调整大小的窗口?
【问题讨论】:
-
我检查了...但正在寻找更多的教程...
-
一个古老但仍然相关的问题:Creating Bordless Windows with custom visual.
如何为 WPF 窗口创建一个基本的自定义窗口镶边,它不包括关闭按钮,但仍然是一个可移动和可调整大小的窗口?
【问题讨论】:
您设置您的窗口WindowStyle="None",然后构建您自己的窗口界面。您需要构建自己的 Min/Max/Close/Drag 事件处理程序,但仍保留调整大小。
例如:
<Window
WindowState="Maximized"
WindowStyle="None"
WindowStartupLocation="CenterScreen"
MaxWidth="{Binding Source={x:Static SystemParameters.WorkArea}, Path=Width}"
MaxHeight="{Binding Source={x:Static SystemParameters.WorkArea}, Path=Height}"
>
<DockPanel x:Name="RootWindow">
<DockPanel x:Name="TitleBar" DockPanel.Dock="Top">
<Button x:Name="CloseButton" Content="X"
Click="CloseButton_Click"
DockPanel.Dock="Right" />
<Button x:Name="MaxButton" Content="Restore"
Click="MaximizeButton_Click"
DockPanel.Dock="Right" />
<Button x:Name="MinButton" Content="Min"
Click="MinimizeButton_Click"
DockPanel.Dock="Right" />
<TextBlock HorizontalAlignment="Center">Application Name</TextBlock>
</DockPanel>
<ContentControl Content="{Binding CurrentPage}" />
</DockPanel>
</Window>
这里是一些常见窗口功能的示例代码隐藏
/// <summary>
/// TitleBar_MouseDown - Drag if single-click, resize if double-click
/// </summary>
private void TitleBar_MouseDown(object sender, MouseButtonEventArgs e)
{
if(e.ChangedButton == MouseButton.Left)
if (e.ClickCount == 2)
{
AdjustWindowSize();
}
else
{
Application.Current.MainWindow.DragMove();
}
}
/// <summary>
/// CloseButton_Clicked
/// </summary>
private void CloseButton_Click(object sender, RoutedEventArgs e)
{
Application.Current.Shutdown();
}
/// <summary>
/// MaximizedButton_Clicked
/// </summary>
private void MaximizeButton_Click(object sender, RoutedEventArgs e)
{
AdjustWindowSize();
}
/// <summary>
/// Minimized Button_Clicked
/// </summary>
private void MinimizeButton_Click(object sender, RoutedEventArgs e)
{
this.WindowState = WindowState.Minimized;
}
/// <summary>
/// Adjusts the WindowSize to correct parameters when Maximize button is clicked
/// </summary>
private void AdjustWindowSize()
{
if (this.WindowState == WindowState.Maximized)
{
this.WindowState = WindowState.Normal;
MaxButton.Content = "1";
}
else
{
this.WindowState = WindowState.Maximized;
MaxButton.Content = "2";
}
}
【讨论】:
Titlebar 停靠面板上使用 DockPanel.Dock="Top"。
Shell:WindowChrome.CaptionHeight,您不需要任何标题栏单击拖动废话。没有理由重新发明轮子。还保留其他默认窗口行为,例如双击最大化、摇动以独奏。
WindowChrome.CaptionHeight来拥有所有的标题栏功能。 @RandomEngy 与按钮处的WindowChrome.IsHitTestVisibleInChrome="True" 组合将使它们在标题栏区域中可点击。
.NET 4.5 添加了一个新类,大大简化了这一过程。
WindowChrome class 使您能够将 Windows Presentation Foundation (WPF) 内容扩展到通常为操作系统的窗口管理器保留的窗口的非客户区。
您可以找到tutorial here。
【讨论】:
我刚刚将下面的示例用于 .net 4.5,它运行良好。有趣的是,它为点击事件的资源字典使用了代码。您所要做的就是在app.xaml 文件中引用资源字典,然后为窗口分配样式CustomWindowStyle。这是从http://www.eidias.com/blog/2014/1/27/restyle-your-window 无耻地盗取的。
<ResourceDictionary x:Class="WpfApp7.WindowStyle"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="CustomWindowStyle" TargetType="{x:Type Window}">
<Setter Property="WindowChrome.WindowChrome">
<Setter.Value>
<WindowChrome CaptionHeight="30"
CornerRadius="4"
GlassFrameThickness="0"
NonClientFrameEdges="None"
ResizeBorderThickness="5"
UseAeroCaptionButtons="False" />
</Setter.Value>
</Setter>
<Setter Property="BorderBrush" Value="Black" />
<Setter Property="Background" Value="Gray" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Window}">
<Grid>
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="5,30,5,5">
<AdornerDecorator>
<ContentPresenter />
</AdornerDecorator>
</Border>
<Grid Height="30"
VerticalAlignment="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal" Margin="5,0">
<Button Content="A" Margin="0,0,5,0" VerticalAlignment="Center" Click="Button_Click" WindowChrome.IsHitTestVisibleInChrome="True"/>
<Button Content="B" Margin="0,0,5,0" VerticalAlignment="Center" Click="Button_Click" WindowChrome.IsHitTestVisibleInChrome="True"/>
<Button Content="C" Margin="0,0,5,0" VerticalAlignment="Center" Click="Button_Click" WindowChrome.IsHitTestVisibleInChrome="True"/>
<Button Content="D" Margin="0,0,5,0" VerticalAlignment="Center" Click="Button_Click" WindowChrome.IsHitTestVisibleInChrome="True"/>
</StackPanel>
<TextBlock Margin="5,0,0,0"
VerticalAlignment="Center"
HorizontalAlignment="Center"
FontSize="16"
Foreground="White"
Text="{TemplateBinding Title}"
Grid.Column="1"/>
<StackPanel Orientation="Horizontal"
Grid.Column="2">
<Button x:Name="btnClose"
Width="15"
Margin="5"
Click="CloseClick"
Content="X"
WindowChrome.IsHitTestVisibleInChrome="True" />
<Button x:Name="btnRestore"
Width="15"
Margin="5"
Click="MaximizeRestoreClick"
Content="#"
WindowChrome.IsHitTestVisibleInChrome="True" />
<Button x:Name="btnMinimize"
Width="15"
Margin="5"
VerticalContentAlignment="Bottom"
Click="MinimizeClick"
Content="_"
WindowChrome.IsHitTestVisibleInChrome="True" />
</StackPanel>
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
对于后面的代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
namespace WpfApp7
{
public partial class WindowStyle : ResourceDictionary
{
public WindowStyle()
{
InitializeComponent();
}
private void CloseClick(object sender, RoutedEventArgs e)
{
var window = (Window)((FrameworkElement)sender).TemplatedParent;
window.Close();
}
private void MaximizeRestoreClick(object sender, RoutedEventArgs e)
{
var window = (Window)((FrameworkElement)sender).TemplatedParent;
if (window.WindowState == System.Windows.WindowState.Normal)
{
window.WindowState = System.Windows.WindowState.Maximized;
}
else
{
window.WindowState = System.Windows.WindowState.Normal;
}
}
private void MinimizeClick(object sender, RoutedEventArgs e)
{
var window = (Window)((FrameworkElement)sender).TemplatedParent;
window.WindowState = System.Windows.WindowState.Minimized;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("Hello!");
}
}
}
【讨论】:
这是一个简单的解决方案,看起来与默认的 Windows 10 按钮非常相似,它只是为符号使用相同的字体:
<StackPanel Orientation="Horizontal" VerticalAlignment="Top" WindowChrome.IsHitTestVisibleInChrome="True">
<Button Click="Minimize_Click" Content="" FontFamily="Segoe MDL2 Assets" FontSize="10" Padding="15,15,15,5" Background="Transparent" BorderBrush="Transparent" />
<Button Click="Maximize_Click" FontFamily="Segoe MDL2 Assets" FontSize="10" Padding="15,10" Background="Transparent" BorderBrush="Transparent">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Button.Content" Value="" />
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}, Path=WindowState}" Value="Maximized">
<Setter Property="Button.Content" Value="" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
<Button Click="Close_Click" Content="" FontFamily="Segoe MDL2 Assets" FontSize="10" Padding="15,10" Background="Transparent" BorderBrush="Transparent" />
</StackPanel>
如果您想要支持旧的 Windows 版本(7 和 8),请查看此处:https://stackoverflow.com/a/27911618/9758687
【讨论】:
以下是您需要采取的方法的概述:
WindowStyle="None" 来做你自己的 UI。WindowChrome.CaptionHeight 获得标准的标题栏拖动/双击/摇动行为,并在您的按钮上设置WindowChrome.IsHitTestVisibleInChrome="True" 以使其可点击。完整的文章有点长; I go over them in detail with code examples in this blog post.
【讨论】: