方案一
WPF中的无边框透明窗体,由于没有边并且透明,窗体无法进行缩放操作,今天来讲解如何解决这个问题。
先说一下思路,我们先手为该窗体添加4个边,4个角用于缩放操作,然后再为他们写事件,完成拖放操作。
Xaml文件
<Window x:Class="UniversalRobot.Window2" 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:UniversalRobot" mc:Ignorable="d" Title="Window2" Height="300" Width="300" WindowStyle="None" AllowsTransparency="True"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="4"/> <RowDefinition/> <RowDefinition Height="4"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="4"/> <ColumnDefinition/> <ColumnDefinition Width="4"/> </Grid.ColumnDefinitions> <Rectangle Name="ResizeTopLeft" Fill="#01000000" Grid.Row="0" Grid.Column="0" MouseMove="ResizePressed" MouseDown="ResizePressed"/> <Rectangle Name="ResizeTop" Fill="#01000000" Grid.Row="0" Grid.Column="1" MouseMove="ResizePressed" MouseDown="ResizePressed"/> <Rectangle Name="ResizeTopRight" Fill="#01000000" Grid.Row="0" Grid.Column="2" MouseMove="ResizePressed" MouseDown="ResizePressed"/> <Rectangle Name="ResizeLeft" Fill="#01000000" Grid.Row="1" Grid.Column="0" MouseMove="ResizePressed" MouseDown="ResizePressed"/> <Rectangle Name="ResizeRight" Fill="#01000000" Grid.Row="1" Grid.Column="3" MouseMove="ResizePressed" MouseDown="ResizePressed"/> <Rectangle Name="ResizeBottomLeft" Fill="#01000000" Grid.Row="3" Grid.Column="0" MouseMove="ResizePressed" MouseDown="ResizePressed"/> <Rectangle Name="ResizeBottom" Fill="#01000000" Grid.Row="3" Grid.Column="1" MouseMove="ResizePressed" MouseDown="ResizePressed"/> <Rectangle Name="ResizeBottomRight" Fill="#01000000" Grid.Row="3" Grid.Column="2" MouseMove="ResizePressed" MouseDown="ResizePressed"/> </Grid> </Window>
后台代码
namespace UniversalRobot { /// <summary> /// Window2.xaml 的交互逻辑 /// </summary> public partial class Window2 : Window { public Window2() { InitializeComponent(); this.SourceInitialized += delegate (object sender, EventArgs e) { this._HwndSource = PresentationSource.FromVisual((Visual)sender) as HwndSource; }; } private const int WM_SYSCOMMAND = 0x112; private HwndSource _HwndSource; private enum ResizeDirection { Left = 1, Right = 2, Top = 3, TopLeft = 4, TopRight = 5, Bottom = 6, BottomLeft = 7, BottomRight = 8, } private Dictionary<ResizeDirection, Cursor> cursors = new Dictionary<ResizeDirection, Cursor> { {ResizeDirection.Top, Cursors.SizeNS}, {ResizeDirection.Bottom, Cursors.SizeNS}, {ResizeDirection.Left, Cursors.SizeWE}, {ResizeDirection.Right, Cursors.SizeWE}, {ResizeDirection.TopLeft, Cursors.SizeNWSE}, {ResizeDirection.BottomRight, Cursors.SizeNWSE}, {ResizeDirection.TopRight, Cursors.SizeNESW}, {ResizeDirection.BottomLeft, Cursors.SizeNESW} }; private void ResizePressed(object sender, MouseEventArgs e) { FrameworkElement element = sender as FrameworkElement; ResizeDirection direction = (ResizeDirection)Enum.Parse(typeof(ResizeDirection), element.Name.Replace("Resize", "")); this.Cursor = cursors[direction]; if (e.LeftButton == MouseButtonState.Pressed) ResizeWindow(direction); } [DllImport("user32.dll", CharSet = CharSet.Auto)] private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam); private void ResizeWindow(ResizeDirection direction) { SendMessage(_HwndSource.Handle, WM_SYSCOMMAND, (IntPtr)(61440 + direction), IntPtr.Zero); } } }
从代码可以看出,先注册4个边和4个角的MouseMove和MouseDown事件,鼠标移动到拖放内容上时,判断鼠标悬停在那个边上,改变鼠标指针变成相应对象,判断鼠标是否按下,如果按下了,则发送Win32消息,进行拖放操作,从代码中可以看出来最终的拖放还是使用Win32 api来实现,因为,如果完全用wpf的事件进行拖放的话,实在是太慢了。
方案二
进一步,把该功能封装到自己的类中。