随笔开始之前,要感谢斯克迪亚(http://www.cnblogs.com/SkyD/)他本人热心的帮助,他的文章对我有一定启发性。同时推荐大家去看看CodeProject上的http://www.codeproject.com/KB/WPF/WPFDiagramDesigner_Part1.aspx文章,拖放办法是从那里的copy过来的,WPFDiagramDesigner系列对很多初学者应该是个很好的代码教材,感谢其作者。
I. 简单的开始
刚开始学习WPF几天,发现实现不规则窗体的拖放非常简单。网上普遍的办法就是
不规则窗体的显示办法:
WindowStyle="None"
Background="Transparent"
再给window里添加MouserLeftButtonDown事件处理函数,函数里就加一个DragMove函数就完成了。
II. 妄想
由于平常为了节省系统资源,总是禁用“拖拉时显示窗口内容”这系统选项。使得拖动窗体时出现一个原窗体大小的矩形虚框。某次拖放Yahoo的日历Widget却发现没有这虚框出现,不受禁用“拖拉时显示窗口内容”的限制。
拖放时出现虚框
Widget不会出现这种情况
在winform中实现这个并不是很难,既然现在学习WPF,就在WPF上实现吧。
Window1.xaml内容
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300"
AllowsTransparency="True"
WindowStyle="None"
Background="Transparent"
Loaded="Window_Loaded">
<Window.Resources>
<ControlTemplate x:Key="ThumbTemplate" TargetType="Thumb">
<Rectangle Fill="Transparent"/>
</ControlTemplate>
<ControlTemplate x:Key="DragWindowTemplate" TargetType="ContentControl">
<Grid>
<Thumb Template="{StaticResource ThumbTemplate}" DragDelta="Thumb_DragDelta"/>
<ContentPresenter Content="{TemplateBinding ContentControl.Content}"/>
</Grid>
</ControlTemplate>
</Window.Resources>
<Canvas>
<ContentControl Height="300" Width="300" Template="{StaticResource DragWindowTemplate}">
<Rectangle Fill="Black" Height="300" Width="300" RadiusX="20" RadiusY="20" Opacity="0.55" IsHitTestVisible="False" />
</ContentControl>
<Label Foreground="White" Name="position" BorderThickness="0" HorizontalContentAlignment="Center">不受禁用“拖拉时显示窗口内容”限制</Label>
</Canvas>
</Window>
Window1.xaml.cs内容
{
[DllImport("User32.dll", SetLastError = true)]
internal static extern int SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, int Flags);
/// <summary>
/// 移动窗体的API
/// </summary>
/// <param name="hWnd">窗体句柄</param>
/// <param name="X">X坐标</param>
/// <param name="Y">Y坐标</param>
/// <param name="nWidth">窗体宽</param>
/// <param name="nHeight">窗体高</param>
/// <param name="bRepaint">是否重绘</param>
/// <returns></returns>
[DllImport("User32.dll", SetLastError = true)]
internal static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
private int originalTop; // 记录窗体原来的位置
private int originalLeft; // 记录窗体原来的位置
private WindowInteropHelper wIH; // WPF与Win32代码间互操作的类,这里用来获取窗体句柄
public Window1()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
originalTop = (int)this.Top;
originalLeft = (int)this.Left;
wIH = new WindowInteropHelper(this); //初始化wIH
MoveWindow(wIH.Handle, originalTop, originalLeft, (int)this.Width, (int)this.Height, false);
}
private void Thumb_DragDelta(object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e)
{
originalTop += (int)e.HorizontalChange;
originalLeft += (int)e.VerticalChange;
MoveWindow(wIH.Handle, originalTop, originalLeft, (int)this.Width, (int)this.Height, false);
}
}
III. 总结:还是不够好!
效果是实现了,但还是不完美,还存在几个问题:
1. 首先是在Thumb_DragDelta事件函数里直接使用窗体this.Top += e.HorizontalChange这种方式来控制窗体在屏幕的位置,会出大问题!因为只要这样做,e.HorizontalChange就会立即根据新的Top进行改变,进而使得Top的值以难以想象的加速度提升(this.Left也是如此),因为这里采用了的Win32 API来进行窗体移动(感觉有点不WPF了-_-b)。
2. 就是用了API之后,第一次点击窗体时会出现一次闪动,之后就不会再出现。虽然不知道是什么原因(希望高手能告诉我),但经过实践证明,在loaded事件实现一次API,就会消除这种情况。
3. <Rectangle>等与<Image>拖放时绘制速度貌似有差异,希望是错觉,总体拖放感觉还是没有widget的平滑。希望日后能改进。
引用來源:http://www.cnblogs.com/jinkeungsiu/archive/2008/11/04/1326585.html












Recommend to Front page
未分類(1)
Comment Permissions: Allow commenting