Giter Site home page Giter Site logo

fluentdragdrop's Introduction

Fluent Drag&Drop

NuGet Status ๐Ÿ”† Now with effects

Drag&Drop in WinForms is cumbersome and error-prone. There are multiple events to handle, members to track and properties to set on at least two controls. Passing data is kind of special and you don't get preview images while dragging things around.

Wouldn't it be great if you could use Drag&Drop with fluent code like this?

private void picControlPreviewBehindCursor_MouseDown(object sender, MouseEventArgs e)
{
	var pic = (PictureBox)sender;

	pic.InitializeDragAndDrop()
		.Copy()
		.Immediately()
		.WithData(pic.Image)
		.WithPreview().BehindCursor()
		.To(PreviewBoxes, (target, data) => target.Image = data);

	// Copy(), Move() or Link() to define allowed effects
	// Immediately() or OnMouseMove() for deferred start on mouse move
	// WithData() to pass any object you like
	// WithPreview() to define your preview and how it should behave
	//     BehindCursor() or RelativeToCursor() to define the preview placement
	// To() to define target controls and how the dragged data should be used on drop
}

snippet source | anchor

It's all in there: Putting data to the drag&drop operation, attaching a custom preview image to the mouse cursor, working with the dragged data once it's dropped and much more.

Screenshot

Did you notice that you can even update preview images and their opacity at any time while dragging? ๐Ÿ˜‰

Perfect by default

In real world apps, Drag&Drop should not start at MouseDown because the control selection might not be up to date to the mouse interaction. Instead, developers typically have to keep track that MouseDown did happen and add an additional event handler to MouseMove. If MouseMove is triggered and there was a MouseDown but no MouseUp, the user pressed the mouse button and moved the mouse. So that's when he wanted to start a Drag&Drop operation.

Careful developers won't track a flag whether the mouse button is still down or not but the location where the user pressed the button. On MouseMove, they can then calculate the distance how much the cursor did move. Having a few pixels buffer here helps to prevent the user from accidential Drag&Drop operations.

FluentDrag&Drop does exactly that if defined with OnMouseMove(). However there is no flag or location to track. Methods like WithData() won't accept direct variables to be passed anymore, instead they require a function which gets called as soon as the mouse move is detected later on - if the user pressed and held the mouse button and if he moved a few pixels. Additionally, the developer has the possibility to validate the input like a valid control selection with If(). Of course, this gets called just like WithData() as soon as the user moves the mouse accordingly:

private void CountryList_MouseDown(object sender, MouseEventArgs e)
{
	var source = (ListView)sender;
	var target = source.Equals(listLeft) ? listRight : listLeft;

	source.InitializeDragAndDrop()
		.Move()
		.OnMouseMove()
		.If(() => source.SelectedIndices.Count > 0)
		.WithData(() => source.SelectedItems.OfType<ListViewItem>().ToArray())
		.WithPreview((_, data) => RenderPreview(data)).BehindCursor()
		.To(target, MoveItems);
}

snippet source | anchor

This (and the 5 line method MoveItems()) is everything we need to implement two-way Drag&Drop lists:

Screenshot

Compatibility

FluentDrag&Drop can easily be used with your current Drag&Drop implementations if you want. The following animation shows how it works in combination with traditional Drag&Drop implementations as we know with events like DragEnter, DragOver and DragDrop:

Screenshot

Smoothness

Most approaches I have used in the past get in trouble when moving the preview over controls that do not have the property AllowDrop set to true. Whenever a Drag&Drop implementation uses the GiveFeedback event to update its preview images, you might get laggy Drag&Drop experiences with stuttering preview image movements.

In contrast, FluentDrag&Drop will render preview images smoothly wherever you move them, even over other applications.

๐Ÿ”† Effects

To make your drag and drop implementation even more impressive, this repository also contains a project called "FluentDragDrop.Effects". It is part of the FluentDrag&Drop solution but builds to a separate and optional package which extends FluentDrag&Drop with a set of default effects.

Some of these effects are:

  • FadeIn
  • FadeOut
  • ReturnOnCancel
  • MorphToTarget

Effects

The sample above shows some of the effects in action:

  • FadeIn on start
  • ReturnOnCancel when dropping next to the empty box
  • MorphToTarget when dropping into the empty box
    • this effect is accompanied by an additional effect implemented in the sample app causing the box to fade a color

FluentTransitions

Those effects are powered by another project called FluentTransitions allowing the animations and transitions to be rendered smoothly. I'd encourage you to check it out:


Images taken from Unsplash, links to these are located at /doc/Unsplash.

fluentdragdrop's People

Contributors

actions-user avatar awaescher avatar lakritzator avatar simoncropp avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

fluentdragdrop's Issues

End preview and/or DrapDrop operation in DrapDrop handler

My use case:

  • attach data to the DragDrop operation
  • in the DragDrop handler directly use the data AND create a runtime created modal form which uses the data

Problem:
If a new form is created directly in the event handler the preview still persists.
Is there any chance to end the DragDrop operation in the DragDrop handler?

Below my simplified DragDrop handler which illustrates the problem. The form may be any empty form.

private void PictureBox_DragDrop(object sender, DragEventArgs e)
{
    PictureBox pb = sender as PictureBox;
    if (pb == null) return;

    // allow valid format/object
    var data = e.Data.GetData(e.Data.GetFormats()[0]);
    if (!typeof(DnDArgs).IsAssignableFrom(data.GetType()))
        return;

    DnDArgs args = data as DnDArgs;

    using (FrmTest frmTest = new FrmTest())
    {
        frmTest.ShowDialog(this);
    }

    pb.Image = args.MyImage;
}

Make all data and preview methods deferred

There are several overloads to define the data and the preview images for the Drag&Drop operation.
Make them all deferred so that the library has the possibility to execute those methods as soon as the drag&drop operation starts.
There is no need to execute them immediately on each MouseDown if the configuration is set up to OnMouseMove.

Add hooks to do something before and after the drag started and ended

Slightly related to #14 : The only clean option to update the UI once a drag&drop operation ended is using the To() extension that provides a Func to define what happens once the user finishes the drag&drop operation successfully.

pic.InitializeDragAndDrop()
  .Copy()
  .OnMouseMove()
  .WithData(() => pic.Image)
  .To(PreviewBoxes, (target, data) =>
  {
    target.Image = data;
    MessageBox.Show("...");        //  <-----
  });

However, if the target controls are not known while initializing the drag&drop operation, To() cannot be used. And then, there's no clean way to react on the operation once it is finished.
In addition, there's no clean way to update the UI as soon as a (deferred) drag operation stars, except a workaround which is updating it within the lambda to define the data to drag:

pic.InitializeDragAndDrop()
  .Copy()
  .OnMouseMove()
  .WithData(() => 
  {
    UpdateUi();        //  <-----
    return pic.Image;
  })
  .To(PreviewBoxes, (target, data) =>
  {
    target.Image = data;
    MessageBox.Show("...");
  });

Provide hooks (within the UI thread):

  • Start of the operation
  • End of the operation (bool wasCanceled)

Proposal:

pic.InitializeDragAndDrop()
  .Copy()
  .OnMouseMove()
  .WithData(() => pic.Image)
  .To(PreviewBoxes, (target, data) => target.Image = data)
  .OnStart(() => UpdateUi())
  .OnEnd(success => MessageBox.Show(success ? "Done" : "Canceled"));

how to let me drop object to the not predecided control

This Dragdrop is awesome.
In my case , i want to drop one usercontrol to other control , now i can drog and move one control , but the target object can't not be decided , i may drop to A or B or C , can you give some hint how to do ? thank you very much !

Add Examples for dragging of UserControls and Reordering them

Im currently trying out this Packet and I'm loving it so far.

As there is no documentation except the nice Example Project, I would love to see examples for Drag and Drop of UserControls inside of Panels and also how to reorder them.

Here is what i figured out myself the hard way:

In the UserControl:

        private void UC1_MouseDown(object sender, MouseEventArgs e)
        {
            var parentPanel = this.Parent;
            var parentForm = parentPanel.Parent;
            var targetPanel = parentForm.Controls.Find("panelA", true).FirstOrDefault();

            if (parentPanel != targetPanel) { 
                // Drop into different Panel
                this.InitializeDragAndDrop()
                    .Move()
                    .OnMouseMove()
                    .WithData(() => this)
                    .WithPreview((_, item) => this.GetDragPreview()).RelativeToCursor()
                    .To(targetPanel, DropItemInTargetControl);
            }
            else
            {
                // Reorder in current Panel
                this.InitializeDragAndDrop()
                    .Move()
                    .OnMouseMove()
                    .WithData(() => this)
                    .WithPreview((_, item) => this.GetDragPreview()).RelativeToCursor()
                    .To(targetPanel, DropItemReorder);
            }
        }

        private void DropItemInTargetControl(Control target, Control item)
        {
            target.Controls.Add(item);
        }

        private void DropItemReorder(Control target, Control item)
        {
            var startIndex = this.Parent.Controls.GetChildIndex(this, false);
            Point destionationPoint = target.PointToClient(Cursor.Position);
            var targetIndex = target.GetChildAtPoint(destionationPoint) != null ? target.Controls.GetChildIndex(target.GetChildAtPoint(destionationPoint), false) : target.Controls.Count - 1;

            if (targetIndex != startIndex)
            {
                target.Controls.SetChildIndex(item, targetIndex);
            }
        }

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.