views:

86

answers:

0

I was recently adding some drag/drop functionality to a usercontrol that I'm creating, and I decided that it made sense to factor the specifics of drag/drop out for subsequent testing, etc. The core logic is in DragOnMouseMove<TInput>().

(Formatting trimmed for brevity)

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;
    }
}

Usage would then be something like:

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();
}

Given that I haven't generalized it yet (if comments here are positive and I need something like this a second time, I probably will), is this reasonable for production code, or am I being a Complicator? If you saw this in code you were maintaining, would you call me nasty names? :)

All comments are welcome, including name suggestions. (I don't really like DragState) :)

For example, assuming that this is a good idea at all, I'm not sure yet whether it makes more sense to make the extensibility points functional in parms (via Func<> and Action<> like it is now) or OO (via an abstract DragStateBase with mandatory overrides like OnGenerateData<TInput>(TInput parm) and OnDropCompleted(DragDropEffects result).)