最近做的某个功能需要用到边缘停靠,WPF实现了下,效果如下
主要实现原理如下:
1、增加一块热点区域,鼠标进入时,触发显示动画,并隐藏热点区域
2、鼠标拖动或离开窗体,判断窗体离屏幕边缘的距离,符合条件的,触发隐藏动画,并显示热点区域
3、使用Window.Left属性进行窗体动画
需要注意的地方:
1、在拖动窗体时,不能通过窗体的Left属性来进行判断,因为Left没有刷新,可以通过Win32 API 函数GetWindowRect来获取
2、可以增加缓动动画,使动画效果更好。
实现代码如下:
MainWindow.xaml
在XAML里定义了显示和隐藏的动画,窗体定义了两列,第一列就是隐藏时用于显示窗体的热点区域
<blur:BlurWindow x:Class="WpfDockDemo.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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfDockDemo"
xmlns:blur="clr-namespace:TianXiaTech;assembly=BlurWindow"
mc:Ignorable="d"
Title="MainWindow" Height="650" Width="305" TitleVisibility="Collapsed" IconVisibility="Collapsed" ControlBoxVisibility="Collapsed"
Background="White" Name="main" MouseMove="BlurWindow_MouseMove" MouseLeave="main_MouseLeave" Topmost="True" PreviewMouseDown="main_MouseDown">
<blur:BlurWindow.Resources>
<Storyboard x:Key="hiddenAnimation">
<DoubleAnimation Storyboard.TargetName="main" Storyboard.TargetProperty="(Window.Left)" Duration="0:0:0.5" AutoReverse="False">
<DoubleAnimation.EasingFunction>
<BackEase Amplitude="0.3"/>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
<Storyboard x:Key="showAnimation">
<DoubleAnimation Storyboard.TargetName="main" Storyboard.TargetProperty="(Window.Left)" Duration="0:0:0.5" AutoReverse="False">
<DoubleAnimation.EasingFunction>
<BackEase Amplitude="0.3" />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</blur:BlurWindow.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="5"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid Background="Transparent" MouseEnter="grid_DockArea_MouseEnter" Name="grid_DockArea" Visibility="Collapsed">
<Border Height="{Binding ElementName=main,Path=ActualHeight}" VerticalAlignment="Center" Width="2" Background="Silver">
<Border.Effect>
<DropShadowEffect Color="Black" Opacity=".3"></DropShadowEffect>
</Border.Effect>
</Border>
</Grid>
<!--网上随便找的图-->
<Image Margin="10" Source="https://pic1.zhimg.com/80/v2-46ae37aad7cb70b4dc4ad4489cdaffdd_720w.webp?source=2c26e567" Grid.Column="1" PreviewMouseDown="main_MouseDown" >
<Image.Effect>
<DropShadowEffect Opacity=".5"></DropShadowEffect>
</Image.Effect>
</Image>
</Grid>
</blur:BlurWindow>
引入用到的api函数
public struct POINT
{
public int x;
public int y;
}
public struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
public class User32
{
[DllImport("User32.dll")]
public static extern int GetCursorPos(ref POINT point);
[DllImport("User32.dll")]
public static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect);
}
定义一些用于记录窗体状态的变量
1 private bool isDocking = true; //是否启用边缘停靠 2 private bool isAnimation = false; //是否正在动画中 3 private bool isDraged = false; //是否正在拖动中
定义用于窗体显示和隐藏动画的函数
private void HideWindow(double left = -1)
{
if (left == -1)
{
RECT rect = new RECT();
User32.GetWindowRect(new WindowInteropHelper(this).Handle, ref rect);
left = rect.left;
}
if (SystemParameters.PrimaryScreenWidth - left - this.Width > 15)
return;
if (isAnimation)
return;
isAnimation = true;
hiddenAnimation.Begin();
}
private void ShowWindow()
{
if (isAnimation)
return;
grid_DockArea.Visibility = Visibility.Collapsed;
isAnimation = true;
showAnimation.Begin();
}
处理鼠标移动事件
private void BlurWindow_MouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
try
{
this.DragMove();
isDraged = true;
}
catch
{
}
}
if (e.LeftButton == MouseButtonState.Released && isDocking == true && isDraged == true)
{
POINT point = new POINT();
if (User32.GetCursorPos(ref point) == 1)
{
var pos = e.GetPosition(this);
if (pos.X < 0 && pos.Y < 0)
HideWindow();
}
isDraged = false;
}
}
处理鼠标按下事件
1 private void main_MouseDown(object sender, MouseButtonEventArgs e) 2 { 3 var pos = e.GetPosition(this); 4 if (pos.X >= 0 && pos.Y >= 0) 5 isDraged = true; 6 }
处理鼠标离开事件
1 private void main_MouseLeave(object sender, MouseEventArgs e) 2 { 3 if (isDocking && isDraged == false) 4 { 5 HideWindow(); 6 } 7 }
这样就可以实现了一个简单的边缘停靠效果。现在只实现了屏幕右侧的边缘停靠,左边和上面可以如法炮制。
窗体第一次运行是不会主动隐藏的,需要手动控制 一下。
标签:动画,int,private,边缘,窗体,停靠,WPF,true,public From: https://blog.csdn.net/zhaotianff/article/details/140769607