WPF:控件带阴影地任意拖动【转】

使用户能改变控件的位置,早已不是稀奇的事儿了。最近在WPF下实现了这一功能,并且尝试使用VisualBrush实现了拖动时的阴影效果。

首先实例化一个Canvas布局:

<Canvas x:Name="c" MouseDown="c_MouseDown " MouseMove="c_MouseMove " MouseUp="c_MouseUp "></Canvas>

接着就是代码部分:注释在代码里面了

Code:
  1.    public partial class Window1 : Window   
  2.      {   
  3.         private bool dragging;   
  4.          Point mousePoint;   
  5.          Rectangle shadow = new Rectangle();//显示控件阴影的矩形   
  6.            
  7.          Control mouseCtrl = null;//被拖动的控件   
  8.   
  9.         public Window1()   
  10.          {   
  11.              InitializeComponent();   
  12.              FullScreenManager.RepairWpfWindowFullScreenBehavior(this);   
  13.              dragging = false;           
  14.              shadow.Opacity = 0.5;  //阴影加点透明度       
  15.              c.Children.Add(shadow);//阴影加入canvas   
  16.              shadow.Visibility = Visibility.Hidden ;//隐藏shadow   
  17.         }   
  18.   
  19.         private void c_MouseDown(object sender, MouseButtonEventArgs e)   
  20.          {   
  21.            if (e.LeftButton == MouseButtonState.Pressed)   
  22.              {   
  23.                  dragging = true;//标记鼠标按下   
  24.                  mousePoint = e.GetPosition(this.c);//获取鼠标在但前canvas内的位置   
  25.                  mouseCtrl = (Control)e.Source;   //获得事件触发的源,即哪个控件     
  26.                  VisualBrush v;   
  27.                  v = new VisualBrush(mouseCtrl);//利用VisualBrush得到控件的影像   
  28.                  shadow.Width = mouseCtrl.Width;   
  29.                  shadow.Height = mouseCtrl.Height;   
  30.                  shadow.Fill = v;//将影像填充给矩形   
  31.                  Canvas.SetLeft(shadow, Canvas.GetLeft(mouseCtrl));   
  32.                  Canvas.SetTop(shadow, Canvas.GetTop(mouseCtrl));   
  33.                  shadow.Visibility = Visibility.Visible;//使矩形可见   
  34.                 //Canvas.SetZIndex(shadow, 0);//可以通过SetZIndex设置阴影的z方向位置   
  35.                  c.CaptureMouse();//强制捕获鼠标。这在对于背景透明的窗体里面是必须的   
  36.              }   
  37.          }   
  38.   
  39.         private void c_MouseMove(object sender, MouseEventArgs e)   
  40.          {   
  41.             if (dragging)   
  42.              {   
  43.                 if (e.LeftButton == MouseButtonState.Pressed)   
  44.                  {   
  45.                      Point theMousePoint = e.GetPosition(this.c);   
  46.                      Canvas.SetLeft(shadow, theMousePoint.X - (mousePoint.X - Canvas.GetLeft(shadow)));   
  47.                      Canvas.SetTop(shadow, theMousePoint.Y - (mousePoint.Y - Canvas.GetTop(shadow)));//简单的计算,只移动shadow   
  48.                      mousePoint = theMousePoint;   
  49.                  }   
  50.              }   
  51.          }   
  52.   
  53.         private void c_MouseUp(object sender, MouseButtonEventArgs e)   
  54.          {   
  55.              dragging = false;   
  56.              Mouse.Capture(null);//取消强制捕获   
  57.              shadow.Visibility = Visibility.Hidden;//隐藏shadow   
  58.              Canvas.SetLeft(mouseCtrl   , Canvas.GetLeft(shadow ));   
  59.              Canvas.SetTop(mouseCtrl   , Canvas.GetTop(shadow ));//将控件放到新的位置   
  60.          }   
  61.      }   

     

     

这里需要说明的是c.CaptureMouse();

首先谈一下我的体会,刚开始没有写这句话,原因是在正常的窗体里面测试的。后来因为需要,将窗体背景设成透明后,发现shadow总是“跟不上”,仔细观察后发现,原因是当鼠标在透明的区域上划过的时候不会响应mousemove事件。所以如果窗体背景不是透明的话,写不写这句话都是一样的。后来在别人的提示下,强制捕获鼠标就解决了这个问题。

并且尽管理论上这段代码具有通用性,也就是任何control下的元素都可以实现拖动。但是对于本身具有click或mousedown事件的元素,例如button,这段代码就不适用了。原因是mousedown事件在遇到这样的元素的时候还没来得及路由给canvas就被捕获了。

在这个实例中还有一点,如果我们在代码里把一个控件实例化,并加到canvas里面后一定要手动设置它在canvas的位置

                        Canvas.SetLeft(t, 0);
                        Canvas.SetTop(t, 0);

否则控件的位置是个“非数”。

posted @ 2010-10-26 16:26  Lester Duo  Views(4183)  Comments(10Edit  收藏  举报