2009-04-24 4 views
1

Ich habe kürzlich eine Drag/Drop-Funktionalität zu einem Benutzersteuerelement hinzugefügt, das ich erstelle, und ich entschied, dass es sinnvoll war, die Besonderheiten von Drag & Drop für nachfolgende Tests usw. zu berücksichtigen. Die Kernlogik ist in DragOnMouseMove<TInput>().Ist dies ein guter Weg, die DragDrop-Logik aus einem Steuerelement heraus zu faktorisieren?

(Formatierung der Kürze getrimmt)

internal class DragState 
{ 
    private static readonly Size deadZoneSize = SystemInformation.DragSize; 
    private Rectangle dragDeadZone = Rectangle.Empty; 
    private Control owningControl = null; 

    public BlockTypeDragState(Control owner) 
    { 
     // null check boilerplate here 
     this.owningControl = owner; 
     return; 
    } 

    private bool IsActive 
    { 
     get { return this.dragDeadZone != Rectangle.Empty; } 
    } 

    public void DragOnMouseMove(
     Point mouseAt, 
     DragDropEffects allowedEffects, 
     Func<object> generateDragData) 
    { 
     this.DragOnMouseMove<object>(
      mouseAt, 
      allowedEffects, 
      null, 
      s => generateDragData()); 
     return; 
    } 

    public void DragOnMouseMove<TInput>(
     Point mouseAt, 
     DragDropEffects allowedEffects, 
     TInput generateParm, 
     Func<TInput, object> generateDragData) 
    { 
     // boilerplate null check on generateDragData 
     if (this.DragShouldStart(mouseAt)) 
     { 
      object data = generateDragData(generateParm); 
      this.owningControl.DoDragDrop(data, allowedEffects); 

      this.Reset(); 
     } 
     return; 
    } 

    public void ListenForDrag(int x, int y) 
    { 
     this.dragDeadZone = new Rectangle(new Point(x - (deadZoneSize.Width/2), y - (deadZoneSize.Height/2)), deadZoneSize); 
     return; 
    } 

    public void Reset() { this.dragDeadZone = Rectangle.Empty; } 

    private bool DragShouldStart(Point mouseClientLocation) 
    { 
     if (this.IsActive && !this.dragDeadZone.Contains(mouseClientLocation)) 
     { return true; } 
     return false; 
    } 
} 

Verwendung wäre dann so etwas wie:

private DragState dragState = new DragState(this); // pseudo 

// MouseMove event handler 
private void HandleMouseMove(object sender, MouseEventArgs e) 
{ 
    // Perform the drag/drop. 
    this.dragState.DragOnMouseMove(
     new Point(e.X, e.Y), 
     DragDropEffects.Copy, 
     () => this.BuildDataToDragDrop()); 

    return; 
} 

private void HandleMouseDown(object sender, MouseEventArgs e) 
{ 
    if (this.CanDragDrop(sender, e)) this.dragState.ListenForDrag(e.X, e.Y); 
} 

private void HandleMouseUp(object sender, MouseEventargs e) 
{ 
    this.dragState.Reset(); 
} 

Da ich habe es noch nicht verallgemeinert (wenn hier Kommentare sind positiv und ich brauche etwas, So ein zweites Mal, werde ich wahrscheinlich), ist das für den Produktionscode sinnvoll, oder bin ich ein Complicator? Wenn du das in Code siehst, den du aufrechterhälttest, würdest du mich böse nennen? :)

Alle Kommentare sind willkommen, einschließlich Namensvorschläge. (Ich mag es nicht wirklich DragState) :)

zum Beispiel angenommen wird, dass dies eine gute Idee überhaupt, ich bin noch nicht sicher, ob es sinnvoller ist, die Erweiterungspunkte funktional in parms zu machen (via Func<> und Action<> wie es jetzt ist) oder OO (über eine abstrakte DragStateBase mit verbindlichen Überschreibungen wie OnGenerateData<TInput>(TInput parm) und OnDropCompleted(DragDropEffects result))

Antwort

0

Einige Punkte:.

0 Steuerung weiß zu viel Details über DragState. Für mich ist es besser, Methoden wie MouseDown(), MouseUp und etc im DragState zu erstellen.

1 Was ist, wenn das Ziehen rückgängig gemacht werden kann?

2 Warum verwenden Sie DoDragDrop in der Klasse DragState?

private void HandleMouseDown(object sender, MouseEventArgs e) { dragState.MouseMove(new Point(e.X,e.Y), (d,e) => DoDragDrop(d,e)); }

3 auf diese Weise Ihre Klasse DragController werden, nicht Staat ziehen.

4 Wenn Sie eine Menge Logik für den DragDrop benötigen, können Sie versuchen, den Zustandsautomaten in den Controller einzubauen.

5 Was ist, wenn Sie ein Auswahlrechteck implementieren müssen? Sie haben fast einen echten Controller für Drag-Drop implementiert, aber es scheint nicht ganz so nützlich zu sein.

6 ListenForDrag hört eigentlich gar nichts. Es hat nur Startpunkt gesetzt :-)

7 dragDeadZone ist ein netter Name. Ich würde es in meinen Zwecken verwenden

8 Was ist, wenn Sie einige zusätzliche Logik benötigen, z. B. Auswählen-Ziehen-Zeigen-Kontextmenü? Auf diese Weise brauchst du nicht den DragController, sondern InpurController. Auf diese Weise kann die gesamte mit der Eingabe zusammenhängende Logik aus der Steuerklasse heraus verschoben und wiederverwendet werden.

Verwandte Themen