2010-07-13 41 views
18

Tôi đang tạo ứng dụng dành cho máy tính để bàn trong C# bằng Windows Forms. Tôi có một Control tùy chỉnh, và tôi muốn có thể kéo và thả nó trong ứng dụng của tôi (không phải bên ngoài). Ngay bây giờ tôi đang thực hiện điều đó với các phương thức DoDragDrop/OnDragOver/OnDragDrop thông thường. Có cách nào để liên tục vẽ điều khiển khi nó được kéo xung quanh - sắp xếp những gì bạn nhìn thấy bằng cách kéo và thả của JQuery không? Tôi muốn kiểm soát thực tế để ở lại tại chỗ, nhưng tôi muốn vẽ một bản sao của sự xuất hiện của nó khi người dùng kéo nó. Lý tưởng nhất là bản sao thậm chí là bán trong suốt, nhưng đó là một "tốt đẹp để có."C# Kéo và thả: Hiển thị mục đã kéo trong khi kéo

Cách duy nhất tôi có thể nghĩ để làm điều này là đặt mã sơn vào phương thức OnPaint của biểu mẫu chính, nhưng điều đó có vẻ giống như một giải pháp không phù hợp. Bất kỳ ý tưởng nào khác? Mọi thứ có dễ dàng hơn không nếu Control tự vẽ như một Bitmap?

Trả lời

14

Tôi nghĩ mình nên quay lại và tự trả lời câu hỏi này, vì cuối cùng tôi đã làm nó hoạt động.

Tôi tạo ra một lớp CursorUtil với các chức năng:

public struct IconInfo { 
    public bool fIcon; 
    public int xHotspot; 
    public int yHotspot; 
    public IntPtr hbmMask; 
    public IntPtr hbmColor; 
} 

public class CursorUtil { 
    [DllImport("user32.dll")] 
    public static extern IntPtr CreateIconIndirect(ref IconInfo icon); 

    [DllImport("user32.dll")] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    public static extern bool GetIconInfo(IntPtr hIcon, ref IconInfo pIconInfo); 

    [DllImport("gdi32.dll")] 
    public static extern bool DeleteObject(IntPtr handle); 

    [DllImport("user32.dll", CharSet = CharSet.Auto)] 
    extern static bool DestroyIcon(IntPtr handle); 

    // Based on the article and comments here: 
    // http://www.switchonthecode.com/tutorials/csharp-tutorial-how-to-use-custom-cursors 
    // Note that the returned Cursor must be disposed of after use, or you'll leak memory! 
    public static Cursor CreateCursor(Bitmap bm, int xHotspot, int yHotspot) { 
     IntPtr cursorPtr; 
     IntPtr ptr = bm.GetHicon(); 
     IconInfo tmp = new IconInfo(); 
     GetIconInfo(ptr, ref tmp); 
     tmp.xHotspot = xHotspot; 
     tmp.yHotspot = yHotspot; 
     tmp.fIcon = false; 
     cursorPtr = CreateIconIndirect(ref tmp); 

     if (tmp.hbmColor != IntPtr.Zero) DeleteObject(tmp.hbmColor); 
     if (tmp.hbmMask != IntPtr.Zero) DeleteObject(tmp.hbmMask); 
     if (ptr != IntPtr.Zero) DestroyIcon(ptr); 

     return new Cursor(cursorPtr); 
    } 

    public static Bitmap AsBitmap(Control c) { 
     Bitmap bm = new Bitmap(c.Width, c.Height); 
     c.DrawToBitmap(bm, new Rectangle(0, 0, c.Width, c.Height)); 
     return bm; 
    } 

Sau đó, tôi đã viết một lớp Kéo (cũng không hướng đối tượng, than ôi, nhưng tôi figured bạn chỉ có thể kéo một điều tại một thời điểm trong một máy tính để bàn ứng dụng).Dưới đây là một chút mã mà:

public static void StartDragging(Control c) { 
     Dragged = c; 
     DisposeOldCursors(); 
     Bitmap bm = CursorUtil.AsBitmap(c); 
     DragCursorMove = CursorUtil.CreateCursor((Bitmap)bm.Clone(), DragStart.X, DragStart.Y);  
     DragCursorLink = CursorUtil.CreateCursor((Bitmap)bm.Clone(), DragStart.X, DragStart.Y);  
     DragCursorCopy = CursorUtil.CreateCursor(CursorUtil.AddCopySymbol(bm), DragStart.X, DragStart.Y); 
     DragCursorNo = CursorUtil.CreateCursor(CursorUtil.AddNoSymbol(bm), DragStart.X, DragStart.Y); 
     //Debug.WriteLine("Starting drag"); 
    } 

    // This gets called once when we move over a new control, 
    // or continuously if that control supports dropping. 
    public static void UpdateCursor(object sender, GiveFeedbackEventArgs fea) { 
     //Debug.WriteLine(MainForm.MousePosition); 
     fea.UseDefaultCursors = false; 
     //Debug.WriteLine("effect = " + fea.Effect); 
     if (fea.Effect == DragDropEffects.Move) { 
      Cursor.Current = DragCursorMove; 

     } else if (fea.Effect == DragDropEffects.Copy) { 
      Cursor.Current = DragCursorCopy; 

     } else if (fea.Effect == DragDropEffects.None) { 
      Cursor.Current = DragCursorNo; 

     } else if (fea.Effect == DragDropEffects.Link) { 
      Cursor.Current = DragCursorLink; 

     } else { 
      Cursor.Current = DragCursorMove; 
     } 
    } 

Bạn có thể sử dụng các phương pháp này khi bạn thiết lập kiểm soát của bạn, ví dụ như trong các nhà xây dựng:

GiveFeedback += new GiveFeedbackEventHandler(Drag.UpdateCursor); 

và trong phương pháp này:

protected override void OnMouseMove(MouseEventArgs mea) { 
     if (Drag.IsDragging(mea)) { 
      Drag.StartDragging(this); 
      DragDropEffects dde = DoDragDrop(Plan, DragDropEffects.Move | DragDropEffects.Copy); 
      Drag.StopDragging(); 
     } 
    } 
+8

Bất kỳ cơ hội nào nhìn thấy mã đầy đủ cho lớp Kéo? TIA, Johnny J. –

2

Thường được xử lý bởi sự kiện GiveFeedback.

+1

Tôi biết đó là nơi tôi có thể gọi lại khi mục được kéo di chuyển, nhưng bạn có nói rằng tôi nên lấy đối tượng Đồ họa và đặt lệnh vẽ trong phương thức đó không? –

+0

Khi tôi sử dụng GiveFeedback, con trỏ nhấp nháy khi tôi ngừng di chuyển chuột. Nhưng trong khi con chuột đang di chuyển, màn hình hiển thị là ok. –

1

Kéo một ImageList vào hình thức của bạn và sử dụng Image List functions để di chuyển nó xung quanh:

  1. Tạo một đối tượng Bitmap kích thước tầm kiểm soát của bạn (nhưng không quá 256x256).
  2. Sao chép hình ảnh của điều khiển của bạn vào Bitmap: sử dụng (Graphics gfx = Graphics.FromImage (bmp)) {gfx.CopyFromScreen (...)}
  3. Thêm nó vào ImageList của bạn.
  4. Gọi ImageList_BeginDrag().
  5. Gọi DoDragDrop()
  6. Trong trình xử lý OnDragMove, hãy gọi ImageList_DragMove() để di chuyển xung quanh khi di chuyển chuột .
  7. Khi DoDragDrop trả về, hãy gọi ImageList_DragLeave().

Tôi đã gọi ImageList_DragEnter() và ImageList_DragLeave(), có vẻ như chuyển đổi tọa độ được sử dụng bởi ImageList_DragMove() sang tọa độ khách hàng, nhưng việc đọc tài liệu cho thấy không cần thiết.

+0

Tôi khá bối rối ở đây. Câu hỏi đặt ra cho C#, nhưng liên kết MSDN mà bạn cung cấp là dành cho C++ không được quản lý. Có một lớp ImageList trong .Net, nhưng nó không có các phương thức BeginDrag, DragMove và DragLeave mà bạn nói nên được gọi. – RenniePet

6

tùy chọn này có thể là một tùy chọn:

private void btntarget_MouseDown(object sender, MouseEventArgs e) 
    {         

     Bitmap bmp = new Bitmap(btntarget.Width, btntarget.Height); 
     btntarget.DrawToBitmap(bmp, new Rectangle(Point.Empty, bmp.Size)); 
     //optionally define a transparent color 
     bmp.MakeTransparent(Color.White); 

     Cursor cur = new Cursor(bmp.GetHicon());         
     Cursor.Current = cur;    

    } 

Điểm phát sóng của con trỏ sẽ được tạo ở giữa hình ảnh

+0

Con trỏ dường như hoàn nguyên về mặc định sau khi phương thức kết thúc. – helrich

+0

vâng nhưng đó là một người thích chơi mong muốn hoặc tôi thiếu một cái gì đó? ý tôi là, sau khi kéo xong hoặc việc hủy bỏ được thực hiện – kaytes

+0

Tình yêu ... Khá đơn giản. –