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)
)