前言
点击窗口任意区域可移动功能,在一些业务场景中会使用到,比如工具条或者球形状的窗口等。在wpf要实现此功能简单形式还是比较容易的,但是有一些细节需要专门处理,比如与按钮的点击事件冲突问题,解决事件冲突问题后拖动的灵敏度,可复用性等。
一、简单拖动
基础的拖动功能直接使用window类的dragmove即可实现:
在window的previewmouseleftbuttondown中调用dragmove即可。
示例如下:
<window previewmouseleftbuttondown="window_previewmouseleftbuttondown" />
void window_previewmouseleftbuttondown(object sender, system.windows.input.mousebuttoneventargs e)
{
dragmove();
}注:本文实现的是窗口任意区域拖动(比如按钮占满整个窗口),不适用于一般窗口拖动,一般窗口拖动请使用mouseleftbuttondown事件
二、事件冲突问题
根据上述方法实现窗口拖动后发现出现了事件冲突,即窗口内的控件无法相应鼠标点击事件了。因为dragmove的内部实现使用了sc_move,使标题栏(win32窗口)捕获鼠标,原本窗口失去鼠标捕获。窗口内的控件无法响应鼠标消息,因此上述简单拖动在有控件的窗口中是不可行的(局部拖动是可行的,但本文讲的是任意区域拖动)。

三、解决方法
解决方法是不在鼠标按下事件中触发拖动,而是在鼠标移动后触发拖动操作。具体步骤如下:
1、注册3个事件如下:
<window previewmouseleftbuttondown="window_previewmouseleftbuttondown"
previewmousemove="window_previewmousemove"
previewmouseleftbuttonup="window_previewmouseleftbuttonup"/>2、定义2个变量记录信息。
point _pressedposition ; bool _isdragmoved = false;
3.记录鼠标按下位置
void window_previewmouseleftbuttondown(object sender, system.windows.input.mousebuttoneventargs e)
{
_pressedposition = e.getposition(this);
}4.鼠标移动触发拖动
void window_previewmousemove(object sender, system.windows.input.mouseeventargs e)
{
if (mouse.leftbutton==mousebuttonstate.pressed && _pressedposition != e.getposition(this))
{
_isdragmoved = true;
dragmove();
}
}5.鼠标弹起屏蔽消息
void window_previewmouseleftbuttonup(object sender, mousebuttoneventargs e)
{
if (_isdragmoved)
{
_isdragmoved = false;
e.handled = true;
}
}四、效果预览

五、使用示例
由于评论区反馈上述方法存在bug,但是无奈笔者始终没有重现,怀疑是使用方法不正确,或者对本博文讲述功能理解上的差异导致的,在此根据上述方法初版原封不动的编写如下使用示例,以说明使用场景以及使用方法。
1、白板的工具条
(1)、mainwindow.xaml
<window x:class="wpfapp3.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:wpfapp3"
mc:ignorable="d"
background="transparent"
allowstransparency="true"
windowstyle="none"
title="mainwindow" height="60" width="410"
previewmouseleftbuttondown="window_previewmouseleftbuttondown"
previewmousemove="window_previewmousemove"
previewmouseleftbuttonup="window_previewmouseleftbuttonup">
<border background="white" cornerradius="25" margin="5">
<border.effect>
<dropshadoweffect shadowdepth="0" blurradius="5" opacity="0.8" color="#aaaaaa"/>
</border.effect>
<stackpanel margin="20,0,0,0" orientation="horizontal">
<radiobutton content="画笔" width="50" height="50" cursor="hand">
<radiobutton.template>
<controltemplate targettype="radiobutton" >
<border background="transparent">
<textblock x:name="txt" background="transparent" textalignment="center" horizontalalignment="center" verticalalignment="center" foreground="#666666" fontsize="18"
text="{templatebinding content}"></textblock>
</border>
<controltemplate.triggers>
<trigger property="ischecked" value="true">
<setter targetname="txt" property="foreground" value="red"></setter>
</trigger>
</controltemplate.triggers>
</controltemplate>
</radiobutton.template>
</radiobutton>
<radiobutton content="矩形" width="50" height="50" cursor="hand">
<radiobutton.template>
<controltemplate targettype="radiobutton" >
<border background="transparent">
<textblock x:name="txt" background="transparent" textalignment="center" horizontalalignment="center" verticalalignment="center" foreground="#666666" fontsize="18"
text="{templatebinding content}"></textblock>
</border>
<controltemplate.triggers>
<trigger property="ischecked" value="true">
<setter targetname="txt" property="foreground" value="red"></setter>
</trigger>
</controltemplate.triggers>
</controltemplate>
</radiobutton.template>
</radiobutton>
<radiobutton content="文本" width="50" height="50" cursor="hand">
<radiobutton.template>
<controltemplate targettype="radiobutton" >
<border background="transparent">
<textblock x:name="txt" background="transparent" textalignment="center" horizontalalignment="center" verticalalignment="center" foreground="#666666" fontsize="18"
text="{templatebinding content}"></textblock>
</border>
<controltemplate.triggers>
<trigger property="ischecked" value="true">
<setter targetname="txt" property="foreground" value="red"></setter>
</trigger>
</controltemplate.triggers>
</controltemplate>
</radiobutton.template>
</radiobutton>
<radiobutton content="箭头" width="50" height="50" cursor="hand">
<radiobutton.template>
<controltemplate targettype="radiobutton" >
<border background="transparent">
<textblock x:name="txt" background="transparent" textalignment="center" horizontalalignment="center" verticalalignment="center" foreground="#666666" fontsize="18"
text="{templatebinding content}"></textblock>
</border>
<controltemplate.triggers>
<trigger property="ischecked" value="true">
<setter targetname="txt" property="foreground" value="red"></setter>
</trigger>
</controltemplate.triggers>
</controltemplate>
</radiobutton.template>
</radiobutton>
<radiobutton content="图片" width="50" height="50" cursor="hand">
<radiobutton.template>
<controltemplate targettype="radiobutton" >
<border background="transparent">
<textblock x:name="txt" background="transparent" textalignment="center" horizontalalignment="center" verticalalignment="center" foreground="#666666" fontsize="18"
text="{templatebinding content}"></textblock>
</border>
<controltemplate.triggers>
<trigger property="ischecked" value="true">
<setter targetname="txt" property="foreground" value="red"></setter>
</trigger>
</controltemplate.triggers>
</controltemplate>
</radiobutton.template>
</radiobutton>
<border margin="10,0,0,0" borderthickness="1,0,0,0" borderbrush="#999999"></border>
<button name="btn_upload" margin="0,0,0,0" content="上传" width="50" height="50" cursor="hand" click="btn_upload_click">
<button.template>
<controltemplate targettype="button" >
<border background="transparent">
<textblock background="transparent" textalignment="center" horizontalalignment="center" verticalalignment="center" foreground="#666666" fontsize="18"
text="{templatebinding content}"></textblock>
</border>
</controltemplate>
</button.template>
</button>
<button name="btn_close" margin="0,0,0,0" content="关闭" width="50" height="50" cursor="hand" click="btn_close_click">
<button.template>
<controltemplate targettype="button" >
<border background="transparent">
<textblock background="transparent" textalignment="center" horizontalalignment="center" verticalalignment="center" foreground="#666666" fontsize="18"
text="{templatebinding content}"></textblock>
</border>
</controltemplate>
</button.template>
</button>
</stackpanel>
</border>
</window>(2)、mainwindow.xaml.cs
using system.windows;
using system.windows.input;
namespace wpfapp3
{
/// <summary>
/// mainwindow.xaml 的交互逻辑
/// </summary>
public partial class mainwindow : window
{
public mainwindow()
{
initializecomponent();
}
point _pressedposition;
bool _isdragmoved = false;
void window_previewmouseleftbuttondown(object sender, system.windows.input.mousebuttoneventargs e)
{
_pressedposition = e.getposition(this);
}
void window_previewmousemove(object sender, system.windows.input.mouseeventargs e)
{
if (mouse.leftbutton == mousebuttonstate.pressed && _pressedposition != e.getposition(this))
{
_isdragmoved = true;
dragmove();
}
}
void window_previewmouseleftbuttonup(object sender, mousebuttoneventargs e)
{
if (_isdragmoved)
{
_isdragmoved = false;
e.handled = true;
}
}
private void btn_upload_click(object sender, routedeventargs e)
{
messagebox.show("上传成功");
}
private void btn_close_click(object sender, routedeventargs e)
{
close();
}
}
}(3)、效果预览

总结
本文介绍了在窗口任意区域点击拖动的方法。简单的拖动是不可行的,往深一步探究,发现了巧妙的解决方法:在鼠标移动时触发拖动。但这也不是一蹴而就的,这是笔者曾经做项目经过了一定的探究最终得以实现,而本文呈现的是优化后的精简版本,易于实现也很好理解,即是所谓的大道至简。
到此这篇关于c# wpf 实现窗口任意区域点击拖动的文章就介绍到这了,更多相关c# wpf窗口拖动内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论