WPF:控件带阴影地任意拖动【转】
使用户能改变控件的位置,早已不是稀奇的事儿了。最近在WPF下实现了这一功能,并且尝试使用VisualBrush实现了拖动时的阴影效果。
首先实例化一个Canvas布局:
<Canvas x:Name="c" MouseDown="c_MouseDown " MouseMove="c_MouseMove " MouseUp="c_MouseUp "></Canvas>
接着就是代码部分:注释在代码里面了
- public partial class Window1 : Window
- {
- private bool dragging;
- Point mousePoint;
- Rectangle shadow = new Rectangle();//显示控件阴影的矩形
- Control mouseCtrl = null;//被拖动的控件
- public Window1()
- {
- InitializeComponent();
- FullScreenManager.RepairWpfWindowFullScreenBehavior(this);
- dragging = false;
- shadow.Opacity = 0.5; //阴影加点透明度
- c.Children.Add(shadow);//阴影加入canvas
- shadow.Visibility = Visibility.Hidden ;//隐藏shadow
- }
- private void c_MouseDown(object sender, MouseButtonEventArgs e)
- {
- if (e.LeftButton == MouseButtonState.Pressed)
- {
- dragging = true;//标记鼠标按下
- mousePoint = e.GetPosition(this.c);//获取鼠标在但前canvas内的位置
- mouseCtrl = (Control)e.Source; //获得事件触发的源,即哪个控件
- VisualBrush v;
- v = new VisualBrush(mouseCtrl);//利用VisualBrush得到控件的影像
- shadow.Width = mouseCtrl.Width;
- shadow.Height = mouseCtrl.Height;
- shadow.Fill = v;//将影像填充给矩形
- Canvas.SetLeft(shadow, Canvas.GetLeft(mouseCtrl));
- Canvas.SetTop(shadow, Canvas.GetTop(mouseCtrl));
- shadow.Visibility = Visibility.Visible;//使矩形可见
- //Canvas.SetZIndex(shadow, 0);//可以通过SetZIndex设置阴影的z方向位置
- c.CaptureMouse();//强制捕获鼠标。这在对于背景透明的窗体里面是必须的
- }
- }
- private void c_MouseMove(object sender, MouseEventArgs e)
- {
- if (dragging)
- {
- if (e.LeftButton == MouseButtonState.Pressed)
- {
- Point theMousePoint = e.GetPosition(this.c);
- Canvas.SetLeft(shadow, theMousePoint.X - (mousePoint.X - Canvas.GetLeft(shadow)));
- Canvas.SetTop(shadow, theMousePoint.Y - (mousePoint.Y - Canvas.GetTop(shadow)));//简单的计算,只移动shadow
- mousePoint = theMousePoint;
- }
- }
- }
- private void c_MouseUp(object sender, MouseButtonEventArgs e)
- {
- dragging = false;
- Mouse.Capture(null);//取消强制捕获
- shadow.Visibility = Visibility.Hidden;//隐藏shadow
- Canvas.SetLeft(mouseCtrl , Canvas.GetLeft(shadow ));
- Canvas.SetTop(mouseCtrl , Canvas.GetTop(shadow ));//将控件放到新的位置
- }
- }
这里需要说明的是c.CaptureMouse();
首先谈一下我的体会,刚开始没有写这句话,原因是在正常的窗体里面测试的。后来因为需要,将窗体背景设成透明后,发现shadow总是“跟不上”,仔细观察后发现,原因是当鼠标在透明的区域上划过的时候不会响应mousemove事件。所以如果窗体背景不是透明的话,写不写这句话都是一样的。后来在别人的提示下,强制捕获鼠标就解决了这个问题。
并且尽管理论上这段代码具有通用性,也就是任何control下的元素都可以实现拖动。但是对于本身具有click或mousedown事件的元素,例如button,这段代码就不适用了。原因是mousedown事件在遇到这样的元素的时候还没来得及路由给canvas就被捕获了。
在这个实例中还有一点,如果我们在代码里把一个控件实例化,并加到canvas里面后一定要手动设置它在canvas的位置
Canvas.SetLeft(t, 0);
Canvas.SetTop(t, 0);
否则控件的位置是个“非数”。