2008-08-26 9 views
15

Czy istnieje prosty sposób na zapewnienie, że po zakończeniu przeciągania i upuszczania zdarzenie MouseUp nie zostanie zjedzone i zignorowane przez framework?DoDragDrop and MouseUp

Znalazłem blogu opisującego one mechanism, ale to wymaga sporo ręcznej księgowości, w tym flagi stanu wiadomości, wydarzeń mouseMove, ręczny „urlopu myszy” Sprawdzanie itp z których wolałbym nie trzeba zaimplementować jeśli można tego uniknąć.

+0

Argh, też mam ten problem. Bardzo denerwujące, jeśli mnie pytasz! –

Odpowiedz

20

Niedawno chciałem umieścić funkcję przeciągnij i upuść w moim projekcie i nie natknąłem się na ten problem, ale byłem zaintrygowany i naprawdę chciałem sprawdzić, czy mogę wymyślić lepszą metodę niż ta opisana w strona, z którą się łączyłeś. Mam nadzieję, że jasno zrozumiałem wszystko, co chciałeś zrobić i ogólnie myślę, że udało mi się rozwiązać problem w znacznie bardziej elegancki i prosty sposób.

Krótko mówiąc, przy takich problemach byłoby świetnie, gdybyś podał kod, abyśmy mogli dokładnie sprawdzić, co próbujesz zrobić. Mówię to tylko dlatego, że założyłem kilka rzeczy o twoim kodzie w moim rozwiązaniu ... więc mam nadzieję, że jest blisko.

Oto kod, który opiszę poniżej:

this.LabelDrag.QueryContinueDrag += new System.Windows.Forms.QueryContinueDragEventHandler(this.LabelDrag_QueryContinueDrag); 
this.LabelDrag.MouseDown += new System.Windows.Forms.MouseEventHandler(this.LabelDrag_MouseDown); 
this.LabelDrag.MouseUp += new System.Windows.Forms.MouseEventHandler(this.LabelDrag_MouseUp); 

this.LabelDrop.DragDrop += new System.Windows.Forms.DragEventHandler(this.LabelDrop_DragDrop); 
this.LabelDrop.DragEnter += new System.Windows.Forms.DragEventHandler(this.LabelMain_DragEnter); 

public partial class Form1 : Form 
{ 
    public Form1() 
    { 
     InitializeComponent(); 
    } 

    private void LabelDrop_DragDrop(object sender, DragEventArgs e) 
    { 
     LabelDrop.Text = e.Data.GetData(DataFormats.Text).ToString(); 
    } 


    private void LabelMain_DragEnter(object sender, DragEventArgs e) 
    { 
     if (e.Data.GetDataPresent(DataFormats.Text)) 
      e.Effect = DragDropEffects.Copy; 
     else 
      e.Effect = DragDropEffects.None; 

    } 

    private void LabelDrag_MouseDown(object sender, MouseEventArgs e) 
    { 
     //EXTREMELY IMPORTANT - MUST CALL LabelDrag's DoDragDrop method!! 
     //Calling the Form's DoDragDrop WILL NOT allow QueryContinueDrag to fire! 
     ((Label)sender).DoDragDrop(TextMain.Text, DragDropEffects.Copy); 
    } 

    private void LabelDrag_MouseUp(object sender, MouseEventArgs e) 
    { 
     LabelDrop.Text = "LabelDrag_MouseUp"; 
    } 

    private void LabelDrag_QueryContinueDrag(object sender, QueryContinueDragEventArgs e) 
    { 
     //Get rect of LabelDrop 
     Rectangle rect = new Rectangle(LabelDrop.Location, new Size(LabelDrop.Width, LabelDrop.Height)); 

     //If the left mouse button is up and the mouse is not currently over LabelDrop 
     if (Control.MouseButtons != MouseButtons.Left && !rect.Contains(PointToClient(Control.MousePosition))) 
     { 
      //Cancel the DragDrop Action 
      e.Action = DragAction.Cancel; 
      //Manually fire the MouseUp event 
      LabelDrag_MouseUp(sender, new MouseEventArgs(Control.MouseButtons, 0, Control.MousePosition.X, Control.MousePosition.Y, 0)); 
     } 
    } 

} 

Mam pominąć większość kodu projektanta, ale zawarte w link Event Handler się kod, dzięki czemu można mieć pewność, co jest związane z czego. W moim przykładzie przeciągnięcie/upuszczenie występuje między etykietami LabelDrag i LabelDrop.

Głównym elementem mojego rozwiązania jest użycie zdarzenia QueryContinueDrag. To zdarzenie jest wywoływane, gdy stan klawiatury lub myszy zmienia się po wywołaniu funkcji DoDragDrop na tym sterowaniu. Być może już to robisz, ale bardzo ważne jest, aby wywołać metodę DoDragDrop kontrolki, która jest Twoim źródłem, a nie metodę powiązaną z formularzem. W przeciwnym razie QueryContinueDrag NIE uruchomi się!

Należy pamiętać, że QueryContinueDrag uruchomi się automatycznie po zwolnieniu myszy na kontrole drop, więc musimy się upewnić, że na to pozwolimy. Jest to obsługiwane przez sprawdzenie, czy pozycja myszy (pobrana z globalną właściwością Control.MousePosition) znajduje się wewnątrz prostokąta kontrolnego LabelDrop. Musisz także przekonwertować MousePosition na punkt odnoszący się do okna klienta z PointToClient jako Control.MousePosition zwraca względną pozycję ekranu.

Więc zaznaczając, że mysz jest nie nad kontrolą rozwijanego, a przycisk myszy jest teraz się mamy skutecznie przechwycone zdarzenie mouseUp za kontrolę LabelDrag! :) Teraz możesz po prostu zrobić przetwarzanie, które chcesz tutaj zrobić, ale jeśli masz już kod, którego używasz w procedurze obsługi zdarzenia MouseUp, nie jest to wydajne. Więc po prostu wywołaj zdarzenie MouseUp stąd, przekazując mu niezbędne parametry, a obsługa myszy MouseUp nigdy nie będzie znała różnicy.

Tylko uwaga choć, jak ja to nazywam DoDragDrop z ciągu obsługi zdarzeń MouseDown w moim przykładzie, kod ten powinien nigdy rzeczywiście uzyskać bezpośredni wydarzenie MouseUp na ogień. Po prostu umieściłem tam ten kod, aby pokazać, że można to zrobić.

Nadzieję, że pomaga!

+0

wiele się nauczyłeś od swojego rozwiązania! dzięki! –

+1

Twój pomysł jest świetny, dzięki!Ale myślę, że twoje oświadczenie powinno wyglądać (przycisk może być w czymś innym niż forma, pozbyłem się fałszywego nie): jeśli (Control.MouseButtons! = MouseButtons.Left && rect.Contains (button.Parent.PointToClient (Kontrola .MousePosition))) – colithium

+0

'// NIEZWYKLE WAŻNE - MUSI ZADZWOŃĆ Metodę DoDragDrop firmy LabelDrag!" Dziękuję bardzo! Próbowałem to rozgryźć przez wiele godzin. – Dan