上节回顾
上节已经说到如何创建一个无边框窗体,那么这节就说说如何创建圆角窗体。
开整(分割线搞个仪式)
制作圆角窗体
思路:
圆角窗体比较麻烦,网上的实现思路也五花八门,例如:WinApi直接设置窗口句柄、双窗体重叠、透明窗体+Border等。本文得思路就是透明窗体+Border,因为在本猿测试的时候发现第一种方法很容易出错,句柄不兼容等,第二种方法在Tab切换视图的时候很容易看出来,而且拖动的时候有重影。所以选择第三种,但是第三种也不是最优方案,因为透明窗体很消耗性能,尤其是在窗口上布置很多动画的时候,所以最优方案就是不使用圆角窗体,哈哈哈,但是既然讲到了,那就先做做看吧,因为圆角窗体毕竟很好看。
圆角及阴影
实现圆角的思路采用透明窗体+Border,那么首先第一步需要把窗体变透明,通过设置WindowStyle=“None” ,AllowsTransparency=“True” ,Background=“Transparent”,然后在内容上设置一个Border,然后设置其背景颜色和圆角。阴影的实现就是给Border设置Effect属性,这样不仅可以设置阴影的颜色,还能设置阴影的范围,值得注意的是,阴影的范围应该小于Border的Margin的值,因为不管是什么内容,都不得超出Window的范围。
<Window 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"
Icon="{x:Null}"
WindowStyle="None" AllowsTransparency="True" Background="Transparent"
mc:Ignorable="d">
<Border Background="White" CornerRadius="10" Margin="5">
<Border.Effect>
<DropShadowEffect ShadowDepth="0"/>
</Border.Effect>
</Border>
</Window>
窗体拖动、拖动分屏
拖动操作和上节讲的基本一样,这里就不累述了。
窗体改变尺寸
在上节讲到窗体改变尺寸的操作时,因为Window自带的Border还在,所以这块不需要我们关心,但是在圆角窗体中,这个操作就得自己执行了。我们的实现思路就是追加8个Rect,分别为上、下、左、右、左上、左下、右上、右下,然后每个Rect有自己的执行指令,最后利用WinMessage改变窗口尺寸。当然为以后window重写模板考虑,该处理应该在后台代码实现。
<Window 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"
AllowsTransparency="True"
Background="Transparent"
Icon="{x:Null}"
WindowStyle="None"
mc:Ignorable="d">
<Grid x:Name="windowGrid">
<Border x:Name="mainBorder" Margin="5" Background="White" CornerRadius="10">
<Border.Effect>
<DropShadowEffect ShadowDepth="0" />
</Border.Effect>
</Border>
</Grid>
</Window>
namespace WpfApp1
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.SourceInitialized += MainWindow_SourceInitialized;
}
private enum ResizeDirection
{
Left = 1,
Right = 2,
Top = 3,
TopLeft = 4,
TopRight = 5,
Bottom = 6,
BottomLeft = 7,
BottomRight = 8,
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
RowDefinition row0 = new RowDefinition();
row0.Height = new GridLength(10);
RowDefinition row1 = new RowDefinition();
RowDefinition row2 = new RowDefinition();
row2.Height = new GridLength(10);
ColumnDefinition column0 = new ColumnDefinition();
column0.Width = new GridLength(10);
ColumnDefinition column1 = new ColumnDefinition();
ColumnDefinition column2 = new ColumnDefinition();
column2.Width = new GridLength(10);
windowGrid.RowDefinitions.Add(row0);
windowGrid.RowDefinitions.Add(row1);
windowGrid.RowDefinitions.Add(row2);
windowGrid.ColumnDefinitions.Add(column0);
windowGrid.ColumnDefinitions.Add(column1);
windowGrid.ColumnDefinitions.Add(column2);
mainBorder.SetValue(Grid.RowProperty, 0);
mainBorder.SetValue(Grid.ColumnProperty, 0);
mainBorder.SetValue(Grid.RowSpanProperty, 3);
mainBorder.SetValue(Grid.ColumnSpanProperty, 3);
AddResizeRectangle();
}
protected override void OnPreviewMouseMove(MouseEventArgs e)
{
base.OnPreviewMouseMove(e);
if (e.LeftButton != MouseButtonState.Pressed)
Cursor = Cursors.Arrow;
}
private void AddResizeRectangle()
{
Rectangle rect1 = new Rectangle() { Name = "TopLeft", Fill = Brushes.Transparent };
rect1.SetValue(Grid.RowProperty, 0);
rect1.SetValue(Grid.ColumnProperty, 0);
Rectangle rect2 = new Rectangle() { Name = "Top", Fill = Brushes.Transparent };
rect2.SetValue(Grid.RowProperty, 0);
rect2.SetValue(Grid.ColumnProperty, 1);
Rectangle rect3 = new Rectangle() { Name = "TopRight", Fill = Brushes.Transparent };
rect3.SetValue(Grid.RowProperty, 0);
rect3.SetValue(Grid.ColumnProperty, 2);
Rectangle rect4 = new Rectangle() { Name = "Right", Fill = Brushes.Transparent };
rect4.SetValue(Grid.RowProperty, 1);
rect4.SetValue(Grid.ColumnProperty, 2);
Rectangle rect5 = new Rectangle() { Name = "BottomRight", Fill = Brushes.Transparent };
rect5.SetValue(Grid.RowProperty, 2);
rect5.SetValue(Grid.ColumnProperty, 2);
Rectangle rect6 = new Rectangle() { Name = "Bottom", Fill = Brushes.Transparent };
rect6.SetValue(Grid.RowProperty, 2);
rect6.SetValue(Grid.ColumnProperty, 1);
Rectangle rect7 = new Rectangle() { Name = "BottomLeft", Fill = Brushes.Transparent };
rect7.SetValue(Grid.RowProperty, 2);
rect7.SetValue(Grid.ColumnProperty, 0);
Rectangle rect8 = new Rectangle() { Name = "Left", Fill = Brushes.Transparent };
rect8.SetValue(Grid.RowProperty, 1);
rect8.SetValue(Grid.ColumnProperty, 0);
windowGrid.Children.Add(rect1);
windowGrid.Children.Add(rect2);
windowGrid.Children.Add(rect3);
windowGrid.Children.Add(rect4);
windowGrid.Children.Add(rect5);
windowGrid.Children.Add(rect6);
windowGrid.Children.Add(rect7);
windowGrid.Children.Add(rect8);
foreach (var item in windowGrid.Children)
{
if (item is Rectangle)
{
Rectangle resizeRectangle = (Rectangle)item;
resizeRectangle.PreviewMouseDown += ResizeRectangle_PreviewMouseDown;
resizeRectangle.MouseMove += ResizeRectangle_MouseMove;
}
}
}
private void ResizeRectangle_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
if (this.WindowState == WindowState.Maximized)
{
return;
}
Rectangle rectangle = sender as Rectangle;
if (rectangle != null)
{
switch (rectangle.Name)
{
case "Top":
Cursor = Cursors.SizeNS;
ResizeWindow(ResizeDirection.Top);
break;
case "Bottom":
Cursor = Cursors.SizeNS;
ResizeWindow(ResizeDirection.Bottom);
break;
case "Left":
Cursor = Cursors.SizeWE;
ResizeWindow(ResizeDirection.Left);
break;
case "Right":
Cursor = Cursors.SizeWE;
ResizeWindow(ResizeDirection.Right);
break;
case "TopLeft":
Cursor = Cursors.SizeNWSE;
ResizeWindow(ResizeDirection.TopLeft);
break;
case "TopRight":
Cursor = Cursors.SizeNESW;
ResizeWindow(ResizeDirection.TopRight);
break;
case "BottomLeft":
Cursor = Cursors.SizeNESW;
ResizeWindow(ResizeDirection.BottomLeft);
break;
case "BottomRight":
Cursor = Cursors.SizeNWSE;
ResizeWindow(ResizeDirection.BottomRight);
break;
default:
break;
}
}
}
private void ResizeRectangle_MouseMove(object sender, MouseEventArgs e)
{
if (this.WindowState == WindowState.Maximized)
{
return;
}
Rectangle rectangle = sender as Rectangle;
if (rectangle != null)
{
switch (rectangle.Name)
{
case "Top":
Cursor = Cursors.SizeNS;
break;
case "Bottom":
Cursor = Cursors.SizeNS;
break;
case "Left":
Cursor = Cursors.SizeWE;
break;
case "Right":
Cursor = Cursors.SizeWE;
break;
case "TopLeft":
Cursor = Cursors.SizeNWSE;
break;
case "TopRight":
Cursor = Cursors.SizeNESW;
break;
case "BottomLeft":
Cursor = Cursors.SizeNESW;
break;
case "BottomRight":
Cursor = Cursors.SizeNWSE;
break;
default:
break;
}
}
}
private HwndSource _hwndSource;
private void MainWindow_SourceInitialized(object sender, EventArgs e)
{
_hwndSource = (HwndSource)PresentationSource.FromVisual(this);
}
private void ResizeWindow(ResizeDirection direction)
{
SendMessage(_hwndSource.Handle, 0x112, (IntPtr)(61440 + direction), IntPtr.Zero);
}
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr hWnd, UInt32 msg, IntPtr wParam, IntPtr lParam);
}
}
窗体功能按钮
圆角窗体的功能按钮的创建方式和上节讲的一样,这里也就不累述了。
使用RRQMSkin创建圆角窗体
同样的,以上代码只能实现比较简单的功能,并不完全具备普适性,所以圆角窗体也已经被本猿封装到了RRQMSkin中,如果大家想直接使用的话直接在Nuget搜索RRQMSkin即可,具体操作如下:
添加好引用后,在主窗体替换继承类为RRQMEffectWindow即可(包括后台代码)。
<window:RRQMEffectWindow 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"
CornerRadius="10"
Height="450"
Width="800"
mc:Ignorable="d">
<Grid />
</window:RRQMEffectWindow>
namespace WpfApp1
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : RRQMSkin.Windows.RRQMEffectWindow
{
public MainWindow()
{
InitializeComponent();
}
}
}
结束
OK,一个圆角窗体就创建完成了,今天的分享就到这里吧。
最后希望这篇博客能帮到各位猿友,当然如果还有什么不明白的,可以私信本猿哦,QQ群:234762506