赞
踩
Windows Presentation Foundation (WPF) 是一个可创建桌面客户端应用程序的 UI 框架。 WPF 开发平台支持广泛的应用开发功能,包括应用模型、资源、控件、图形、布局、数据绑定、文档和安全性。 此框架是 .NET Framework 的一部分,因此,在未来如果想快速的开发桌面软件,WPF腚是你的不二选择。
WPF既然是桌面软件UI,那一定绕不开桌面软件的多元化(chan pin jing li de chou pi)显示方式,最常见的就是无边框窗体
、圆角窗体
、窗体阴影
等,同时还需要支持改变窗口大小
、响应拖动分屏
等。本文也会从这几个需求入手,打造一个让各位猿友满意的窗体。
开整(分割线搞个仪式)
思路: 无边框窗体比较好办,思路就是设置窗体属性WindowStyle为None,这时无边框窗体就创建好了,而且支持改变尺寸,但是为了普适性,需要对窗体进行装饰,比如:窗体拖动、拖动分屏、窗体功能按钮、窗体是否支持改变大小等,这些都需要代码参与。
拖动操作一般是在窗体头操作的,所以需要对窗体进行Grid分行。然后在title的Grid里注册鼠标移动事件,然后在后台控制窗体拖动(title的Grid背景色必须赋值,哪怕是透明色,不然不会命中测试)。实际上在调用DragMove方法时,窗体就已经支持了左右分屏以及全屏,但是问题就是:全屏是满屏,把任务栏也遮住了,其次满屏后不能再拖动为正常尺寸。
<Window x:Class="WpfApp1.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WpfApp1" mc:Ignorable="d" WindowStyle="None" Title="Window1" Height="450" Width="800"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="30"/> <RowDefinition/> </Grid.RowDefinitions> <Grid x:Name="title" Background="Transparent" MouseMove="title_MouseMove"> </Grid> <Grid x:Name="body" Grid.Row="1"> </Grid> </Grid> </Window>
namespace WpfApp1 { /// <summary> /// Window1.xaml 的交互逻辑 /// </summary> public partial class Window1 : Window { public Window1() { InitializeComponent(); } private void title_MouseMove(object sender, MouseEventArgs e) { if (e.LeftButton== MouseButtonState.Pressed) { this.DragMove(); } } } }
(1)首先就是最大化遮挡任务栏问题,可以通过重写OnStateChanged事件,在最大化时设置窗体边框以及最大允许尺寸(最大尺寸由工作区域+16组成,16的数字来源于经验),但是由于该事件需要激活,所以需要在Loaded空调用一次。
namespace WpfApp1 { /// <summary> /// Window1.xaml 的交互逻辑 /// </summary> public partial class Window1 : Window { public Window1() { InitializeComponent(); this.Loaded += this.Window1_Loaded; } private void Window1_Loaded(object sender, RoutedEventArgs e) { OnStateChanged(null); } private void title_MouseMove(object sender, MouseEventArgs e) { if (e.LeftButton== MouseButtonState.Pressed) { this.DragMove(); } } protected override void OnStateChanged(EventArgs e) { switch (this.WindowState) { case WindowState.Maximized: this.MaxWidth = SystemParameters.WorkArea.Width + 16; this.MaxHeight = SystemParameters.WorkArea.Height + 16; this.BorderThickness = new Thickness(5); //最大化后需要调整 break; case WindowState.Normal: this.BorderThickness = new Thickness(0); this.MaxWidth = SystemParameters.WorkArea.Width + 16; this.MaxHeight = SystemParameters.WorkArea.Height + 16; break; } } } }
(2)其次解决最大化时拖动问题,我们可以考虑在最大化时拖动时,先设置WindowState为Normal,但是直接这样做会导致鼠标和拖动点之间存在很大间距,所以还需要设置窗体位置。
namespace WpfApp1 { /// <summary> /// Window1.xaml 的交互逻辑 /// </summary> public partial class Window1 : Window { public Window1() { InitializeComponent(); this.Loaded += this.Window1_Loaded; } private void Window1_Loaded(object sender, RoutedEventArgs e) { OnStateChanged(null); } private void title_MouseMove(object sender, MouseEventArgs e) { if (e.LeftButton == MouseButtonState.Pressed) { if (this.WindowState == WindowState.Maximized) { WindowState = WindowState.Normal; Point point = e.MouseDevice.GetPosition(this); Left = point.X - this.title.ActualWidth * point.X / SystemParameters.WorkArea.Width; Top = point.Y - this.title.ActualHeight * point.Y / SystemParameters.WorkArea.Height; } this.DragMove(); } } protected override void OnStateChanged(EventArgs e) { switch (this.WindowState) { case WindowState.Maximized: this.MaxWidth = SystemParameters.WorkArea.Width + 16; this.MaxHeight = SystemParameters.WorkArea.Height + 16; this.BorderThickness = new Thickness(5); //最大化后需要调整 break; case WindowState.Normal: this.BorderThickness = new Thickness(0); this.MaxWidth = SystemParameters.WorkArea.Width + 16; this.MaxHeight = SystemParameters.WorkArea.Height + 16; break; } } } }
窗体的功能按钮是控制窗体的最重要控件。一般的有最小化、正常化切换、最大化三种功能按钮。但是不能直接在title里面直接部署这三个按钮,因为这样的话按钮也会响应拖动命令,这是我们所不希望的。所以必须重新对窗体头布局。然后对按钮注册click事件。
<Window x:Class="WpfApp1.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WpfApp1" mc:Ignorable="d" WindowStyle="None" Title="Window1" Height="450" Width="800"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="30"/> <RowDefinition/> </Grid.RowDefinitions> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition Width="90"/> </Grid.ColumnDefinitions> <Grid x:Name="title" Background="Transparent" MouseMove="title_MouseMove"> </Grid> <StackPanel Grid.Column="1" Orientation="Horizontal"> <Button Content="一" Width="30" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" Click="Button_Click"/> <Button Content="口" Width="30" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" Click="Button_Click_1"/> <Button Content="X" Width="30" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" Click="Button_Click_2"/> </StackPanel> </Grid> <Grid x:Name="body" Grid.Row="1"> </Grid> </Grid> </Window>
namespace WpfApp1 { /// <summary> /// Window1.xaml 的交互逻辑 /// </summary> public partial class Window1 : Window { public Window1() { InitializeComponent(); this.Loaded += this.Window1_Loaded; } private void Window1_Loaded(object sender, RoutedEventArgs e) { OnStateChanged(null); } private void title_MouseMove(object sender, MouseEventArgs e) { if (e.LeftButton == MouseButtonState.Pressed) { if (this.WindowState == WindowState.Maximized) { WindowState = WindowState.Normal; Point point = e.MouseDevice.GetPosition(this); Left = point.X - this.title.ActualWidth * point.X / SystemParameters.WorkArea.Width; Top = point.Y - this.title.ActualHeight * point.Y / SystemParameters.WorkArea.Height; } this.DragMove(); } } protected override void OnStateChanged(EventArgs e) { switch (this.WindowState) { case WindowState.Maximized: this.MaxWidth = SystemParameters.WorkArea.Width + 16; this.MaxHeight = SystemParameters.WorkArea.Height + 16; this.BorderThickness = new Thickness(5); //最大化后需要调整 break; case WindowState.Normal: this.BorderThickness = new Thickness(0); this.MaxWidth = SystemParameters.WorkArea.Width + 16; this.MaxHeight = SystemParameters.WorkArea.Height + 16; break; } } private void Button_Click(object sender, RoutedEventArgs e) { this.WindowState = WindowState.Minimized; } private void Button_Click_1(object sender, RoutedEventArgs e) { if (this.WindowState == WindowState.Normal) { this.WindowState = WindowState.Maximized; } else { this.WindowState = WindowState.Normal; } } private void Button_Click_2(object sender, RoutedEventArgs e) { this.Close(); } } }
实际上以上代码只能实现比较简单的功能,并不完全具备普适性,所以无边框窗体已经被本猿封装到了RRQMSkin中,如果大家想直接使用的话直接在Nuget搜索RRQMSkin即可,具体操作如下:
添加好引用后,在主窗体替换继承类为RRQMWindow即可(包括后台代码)。
<window:RRQMWindow x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WpfApp1"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:window="若汝棋茗_Windows"
Height="450"
Width="800"
mc:Ignorable="d">
<Grid />
</window:RRQMWindow>
namespace WpfApp1
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : RRQMSkin.Windows.RRQMWindow
{
public MainWindow()
{
InitializeComponent();
}
}
}
OK,一个无边框窗体就创建完成了,下节说创建圆角窗体。
最后希望这篇博客能帮到各位猿友,当然如果还有什么不明白的,可以私信本猿哦,QQ群:234762506
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。