2008-10-21 7 views
16

kiểm soát Popup WPF là tốt đẹp, nhưng phần nào giới hạn trong quan điểm của tôi. Có cách nào để "kéo" một popup xung quanh khi nó được mở ra (như với phương thức DragMove() của windows)?Kéo điều khiển WPF Popup

điều này có thể được thực hiện mà không gặp vấn đề gì lớn hay tôi phải tự mình viết thay thế cho lớp bật lên? cảm ơn

Trả lời

13

Đây là giải pháp đơn giản sử dụng ngón tay cái.

  • Subclass Popup trong XAML và codebehind
  • Thêm một Thumb với chiều rộng/chiều cao đặt thành 0 (điều này cũng có thể được thực hiện trong XAML)
  • Nghe MouseDown sự kiện trên Popup và nâng cao cùng một sự kiện trên các Thumb
  • Move cửa sổ bật lên trên DragDelta

XAML:

<Popup x:Class="PopupTest.DraggablePopup" ...> 
    <Canvas x:Name="ContentCanvas"> 

    </Canvas> 
</Popup> 

C#:

public partial class DraggablePopup : Popup 
{ 
    public DraggablePopup() 
    { 
     var thumb = new Thumb 
     { 
      Width = 0, 
      Height = 0, 
     }; 
     ContentCanvas.Children.Add(thumb); 

     MouseDown += (sender, e) => 
     { 
      thumb.RaiseEvent(e); 
     }; 

     thumb.DragDelta += (sender, e) => 
     { 
      HorizontalOffset += e.HorizontalChange; 
      VerticalOffset += e.VerticalChange; 
     }; 
    } 
} 
+0

Có lẽ tôi thiếu một thứ gì đó đơn giản mà nhà phát triển WPF dày dạn biết, nhưng làm cách nào để sử dụng lại? Khi tôi tạo điều khiển trong một ngữ cảnh XAML khác (như cố gắng sử dụng lại nó trong một cửa sổ), bất kỳ nội dung nào tôi chỉ định sẽ ghi đè phần tử Canvas mà ngón tay cái bị ràng buộc. – Vassi

+0

Tôi đã thử giải pháp này. Hoạt động tuyệt vời! Cảm ơn Jacob. Tôi đang gặp phải một vấn đề: Tôi có một cái nhìn bên trong Thumb này và tôi có thể kéo toàn bộ khung nhìn đẹp, tuy nhiên nếu chế độ xem đó có thanh cuộn, thì kéo thanh cuộn đang gây ra việc kéo ngón tay cái và do đó toàn bộ khung nhìn. Có cách nào để tránh điều này không? – Shankar

16

Không có DragMove cho PopUp. Chỉ cần một công việc nhỏ xung quanh, có rất nhiều cải tiến bạn có thể thêm vào điều này.

<Popup x:Name="pop" IsOpen="True" Height="200" Placement="AbsolutePoint" Width="200"> 
    <Rectangle Stretch="Fill" Fill="Red"/>    
</Popup> 

Trong đoạn mã phía sau, thêm sự kiện MouseMove này

pop.MouseMove += new MouseEventHandler(pop_MouseMove); 

    void pop_MouseMove(object sender, MouseEventArgs e) 
    { 
     if (e.LeftButton == MouseButtonState.Pressed) 
     { 
      pop.PlacementRectangle = new Rect(new Point(e.GetPosition(this).X, 
       e.GetPosition(this).Y),new Point(200,200)); 

     } 
    } 
+16

** Ouch **! Không, sử dụng ['Thumb'] (http://msdn.microsoft.com/en-us/library/ms749252%28VS.100%29.aspx) và sự kiện' DragDelta' của nó thay vào đó (opt. 'DragStarted'/'DragCompleted' nếu bạn muốn quản lý các trạng thái). Nó hiệu quả hơn nhiều, sẽ không phân mảnh bộ nhớ và sẽ không có nguy cơ bị mất chuột như ví dụ trên. Đó là cách kéo được thực hiện đúng cách :) Xem [ở đây] (http://www.codeproject.com/KB/WPF/TubePlanner.aspx) để biết ví dụ. – RedGlyph

+0

Tôi đồng ý, giải pháp mà tôi đưa ra chỉ là một hack, Như bạn đã nói, DragDelta hoạt động hiệu quả hơn MoveMove. –

+1

Nhưng nếu bạn không muốn sử dụng sai cửa sổ bật lên dưới dạng ngón tay cái (tôi đoán ý tôi là trong nhận xét của RedGlyph), nhưng muốn di chuyển một cửa sổ bật lên phức tạp hơn (ví dụ: lớp phủ video). sử dụng một cửa sổ rõ ràng không phải là tùy chọn trong kịch bản của tôi. –

0
Private Point startPoint; 

private void Window_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) 
    { 

     startPoint = e.GetPosition(null); 
    } 
private void Window_MouseMove(object sender, MouseEventArgs e) 
    { 
     if (e.LeftButton == MouseButtonState.Pressed) 
     { 
      Point relative = e.GetPosition(null); 
      Point AbsolutePos = new Point(relative.X + this.Left, relative.Y + this.Top); 
      this.Top = AbsolutePos.Y - startPoint.Y; 
      this.Left = AbsolutePos.X - startPoint.X; 
     } 
    } 

này làm việc cho kéo cửa sổ của tôi, nhưng cũng giống như nó đã nói nếu tôi di chuyển chuột để nhanh chóng, nó sẽ thoát ra khỏi của cửa sổ và ngừng tăng sự kiện. Mà không nhắc đến việc kéo thì không trơn tru chút nào. Có ai biết làm thế nào để làm điều đó đúng cách, đẹp và trơn tru kéo, mà không mất nó khi kéo quá nhanh ??? Đăng một ví dụ đơn giản nếu có thể, khác với toàn bộ hướng dẫn sẽ khiến người mới bắt đầu như tôi bị mất trong mã. Cảm ơn!

+0

bạn có thể chụp chuột để tránh sự cố bạn đã đề cập khi chuột thoát khỏi cửa sổ –

2

Một cách khác để đạt được điều này là đặt vị trí của Popup của bạn thành MousePoint. Điều này làm cho cửa sổ bật lên ban đầu xuất hiện ở vị trí của con trỏ chuột.

Sau đó, bạn có thể sử dụng sự kiện Thumb hoặc MouseMove để đặt HorizontalOffset & VerticalOffset của Popup. Các thuộc tính này dịch chuyển Popup ra khỏi vị trí ban đầu của nó khi người dùng kéo nó.

Hãy nhớ đặt lại HorizontalOffset và VerticalOffset về 0 cho lần sử dụng tiếp theo của cửa sổ bật lên!

2

Vấn đề với mất con chuột khi di chuyển quá nhanh, có thể được giải quyết


này được lấy từ MSDN:

Cửa sổ mới chứa trẻ em nội dung của Popup.

Điều khiển bật lên duy trì tham chiếu đến Nội dung con của nó dưới dạng con logic. Khi cửa sổ mới được tạo ra, nội dung của Popup trở thành một đứa trẻ trực quan của cửa sổ và vẫn là con logic của Popup. Ngược lại, Popup vẫn là cha mẹ hợp lý của nội dung Con của nó.


Nói cách khác, con của popup được hiển thị trong cửa sổ độc lập.

Vì vậy, khi thử làm như sau:
Popup.CaptureMouse() đang chụp cửa sổ trình bao bọc chứ không phải cửa sổ bật lên. Thay vào đó, hãy sử dụng Popup.Child.CaptureMouse() để chụp hình thực tế.

Và tất cả các sự kiện khác phải được đăng ký sử dụng Popup.Child.

Giống như Popup.Child.MouseMove, Popup.Child.LostCapture và vân vân

này đã được thử nghiệm và làm việc hoàn toàn tốt đẹp

+0

Có, việc chụp đầu vào chuột là cách thích hợp để xử lý việc kéo. Tất cả điều này e.Leftbutton == Ép là một chút lười biếng và gây ra một số tác dụng phụ. – Alan