Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for drag images and drop descriptions #6576

Merged
merged 103 commits into from
Jul 5, 2022

Conversation

willibrandon
Copy link
Contributor

@willibrandon willibrandon commented Jan 29, 2022

Allow drop targets to display the drag image while the cursor is over the target and add support for setting drop descriptions.

Allow drag sources to specify the drag image bitmap.

Resolves #5884.

Proposed changes

  • Maintain the current default DropTarget behavior. By default, do not display the drag image and drop description.

  • Add a new public enumeration; DropImageType.

namespace System.Windows.Forms
{
    /// <summary>
    /// Specifies the drop description image type.
    /// </summary>
    public enum DropImageType
    {
        /// <summary>
        /// No drop image preference; use the default image.
        /// </summary>
        Invalid = -1,

        /// <summary>
        /// A red bisected circle such as that found on a "no smoking" sign.
        /// </summary>
        None = 0,

        /// <summary>
        /// A plus sign (+) that indicates a copy operation.
        /// </summary>
        Copy = DragDropEffects.Copy,

        /// <summary>
        /// An arrow that indicates a move operation.
        /// </summary>
        Move = DragDropEffects.Move,

        /// <summary>
        /// An arrow that indicates a link.
        /// </summary>
        Link = DragDropEffects.Link,

        /// <summary>
        /// A tag icon that indicates that the metadata will be changed.
        /// </summary>
        Label = 6,

        /// <summary>
        /// A yellow exclamation mark that indicates that a problem has been encountered in the operation.
        /// </summary>
        Warning = 7,

        /// <summary>
        /// Windows 7 and later. Use no drop image.
        /// </summary>
        NoImage = 8
    }
}
  • Add 3 new public DragEventArgs properties; DropImageType, Message, and MessageReplacementToken.
namespace System.Windows.Forms
{
  public class DragEventArgs : EventArgs
  {
      /// <summary>
      /// Gets or sets the drop description image type.
      /// </summary>
      public DropImageType DropImageType { get; set; }
  
        /// <summary>
        /// Gets or sets the drop description text such as "Move to %1" when "Documents" is specified in <see cref="MessageReplacementToken"/>.
        /// </summary>
        /// <remarks>
        /// <para>
        /// UI coloring is applied to the text in <see cref="MessageReplacementToken"/> if used by specifying %1 in <see cref="Message"/>.
        /// </para>
        /// </remarks>
        public string? Message { get; set; }
  
        /// <summary>
        /// Gets or sets the drop description text such as "Documents" when %1 is specified in <see cref="Message"/>.
        /// </summary>
        /// <remarks>
        /// <para>
        /// UI coloring is applied to the text in <see cref="MessageReplacementToken"/> if used by specifying %1 in <see cref="Message"/>.
        /// </para>
        /// </remarks>
        public string? MessageReplacementToken { get; set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="DragEventArgs"/> class.
        /// </summary>
        public DragEventArgs(IDataObject? data, int keyState, int x, int y, DragDropEffects allowedEffect, DragDropEffects effect, DropImageType dropImageType, string message, string messageReplacementToken);
  }
}
  • During the DragEnter event, if the application specifies a DragEventArgs.DropImageType greater than DropImageType.Invalid, display the drag image and drop description.

  • Add 3 new GiveFeedbackEventArgs properties; DragImage, CursorOffset, and UseDefaultDragImage.

namespace System.Windows.Forms
{
  public class GiveFeedbackEventArgs: EventArgs
  {
        /// <summary>
        /// Gets or sets the drag image bitmap.
        /// </summary>
        /// <remarks>
        /// <para>
        /// Note the outer edges of <see cref="DragImage"/> are blended out if the image width or height exceeds 300 pixels.
        /// </para>
        /// </remarks>
        public Bitmap? DragImage { get; set; }

        /// <summary>
        /// Gets or sets the drag image cursor offset.
        /// </summary>
        /// <remarks>
        /// <para>
        /// Specifies the location of the cursor within <see cref="DragImage"/>, which is an offset from the upper-left corner.
        /// </para>
        /// </remarks>
        public Point CursorOffset { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether a layered window drag image is used.
        /// </summary>
        /// <remarks>
        /// <para>
        /// Specify <see langword="true"/> for <see cref="UseDefaultDragImage"/> to use a layered window drag image with a size of 96x96; otherwise
        /// <see langword="false"/>.
        /// </para>
        /// </remarks>
        public bool UseDefaultDragImage { get; set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="GiveFeedbackEventArgs"/> class.
        /// </summary>
        public GiveFeedbackEventArgs(DragDropEffects effect, bool useDefaultCursors, Bitmap? dragImage, Point cursorOffset, bool useDefaultDragImage);
  }
}
  • Add 2 new DoDragDrop methods.
namespace System.Windows.Forms
{
    public partial class Control
    {
        /// <summary>
        /// Begins a drag operation. The <paramref name="allowedEffects"/> determine which drag operations can occur. If the drag operation
        /// needs to interop with applications in another process, <paramref name="data"/> should either be a base managed class
        /// (<see cref="string"/>, <see cref="Bitmap"/>, or <see cref="Drawing.Imaging.Metafile"/>) or some <see cref="object"/> that implements
        /// <see cref="Runtime.Serialization.ISerializable"/>. <paramref name="data"/> can also be any <see cref="object"/> that implements
        /// <see cref="IDataObject"/>. <paramref name="dragImage"/> is the bitmap that will be displayed during the  drag operation and
        /// <paramref name="cursorOffset"/> specifies the location of the cursor within <paramref name="dragImage"/>, which is an offset from the
        /// upper-left corner. Specify <see langword="true"/> for <paramref name="useDefaultDragImage"/> to use a layered window drag image with a
        /// size of 96x96; otherwise <see langword="false"/>. Note the outer edges of <paramref name="dragImage"/> are blended out if the image width
        /// or height exceeds 300 pixels.
        /// <remarks>
        /// <para>
        /// Because <see cref="DoDragDrop(object, DragDropEffects, Bitmap, Point, bool)"/> always performs the RGB multiplication step in calculating
        /// the alpha value, you should always pass a <see cref="Bitmap"/> without premultiplied alpha blending. Note that no error will result from
        /// passing a <see cref="Bitmap"/> with premultiplied alpha blending, but this method will multiply it again, doubling the resulting alpha
        /// value.
        /// </para>
        /// </remarks>
        /// </summary>
        /// <returns>
        /// A value from the <see cref="DragDropEffects"/> enumeration that represents the final effect that was performed during the drag-and-drop
        /// operation.
        /// </returns>
        public DragDropEffects DoDragDrop(object data, DragDropEffects allowedEffects, Bitmap dragImage, Point cursorOffset, bool useDefaultDragImage);
    }

    public abstract partial class ToolStripItem
    {
        /// <summary>
        /// Begins a drag operation. The <paramref name="allowedEffects"/> determine which drag operations can occur. If the drag operation
        /// needs to interop with applications in another process, <paramref name="data"/> should either be a base managed class
        /// (<see cref="string"/>, <see cref="Bitmap"/>, or <see cref="Drawing.Imaging.Metafile"/>) or some <see cref="object"/> that implements
        /// <see cref="Runtime.Serialization.ISerializable"/>. <paramref name="data"/> can also be any <see cref="object"/> that implements
        /// <see cref="IDataObject"/>. <paramref name="dragImage"/> is the bitmap that will be displayed during the  drag operation and
        /// <paramref name="cursorOffset"/> specifies the location of the cursor within <paramref name="dragImage"/>, which is an offset from the
        /// upper-left corner. Specify <see langword="true"/> for <paramref name="useDefaultDragImage"/> to use a layered window drag image with a
        /// size of 96x96; otherwise <see langword="false"/>. Note the outer edges of <paramref name="dragImage"/> are blended out if the image width
        /// or height exceeds 300 pixels.
        /// <remarks>
        /// <para>
        /// Because <see cref="DoDragDrop(object, DragDropEffects, Bitmap, Point, bool)"/> always performs the RGB multiplication step in calculating
        /// the alpha value, you should always pass a <see cref="Bitmap"/> without premultiplied alpha blending. Note that no error will result from
        /// passing a <see cref="Bitmap"/> with premultiplied alpha blending, but this method will multiply it again, doubling the resulting alpha
        /// value.
        /// </para>
        /// </remarks>
        /// </summary>
        /// <returns>
        /// A value from the <see cref="DragDropEffects"/> enumeration that represents the final effect that was performed during the drag-and-drop
        /// operation.
        /// </returns>
        public DragDropEffects DoDragDrop(object data, DragDropEffects allowedEffects, Bitmap dragImage, Point cursorOffset, bool useDefaultDragImage);
    }
}
  • During the DoDragDrop method or the GiveFeedback event, if the application specifies a DragImage bitmap, set CFSTR_INDRAGLOOP to true and initialize the drag-image manager by calling IDragSourceHelper2.InitializeFromBitmap().

  • Load and retrieve the arbitrary private data formats used by the drag-and-drop helpers and manage the storage and release of the related storage mediums using a private DragDropFormat class.

  • Add an internal DragDropHelper class to manage the retrieval of the IDragSourceHelper2 and IDropTargetHelper interface pointers and expose the methods necessary to set and display the drag image and drop description.

  • Add a drag and drop functional test form to the WinformsControlsTest project with files for testing drag and drop operations.

Customer Impact

  • An improved drag-and-drop experience.

Regression?

  • No

Risk

  • I haven't had to work with pointers or allocate/de-allocate memory in the last 13 years, so the risk seems high.

Video

DropTarget_DragImageDropDescription.mp4
DragSource_DragImageDropDescription.mp4
ToolStrip_DragImageDropDescription.mp4
WinForms_DragImageDropDescription.mp4

Test methodology

  • Manually test using WinformsControlsTest as startup project -> Drag and Drop. Click the Open Cats button and drag the cat bitmaps and rich text format file to the picture boxes on the form (see videos).
  • Run unit and integration tests.
  • TODO: Add unit tests.
  • TODO: Add UIIntegration tests.

Accessibility testing

TODO

Test environment(s)

  • .NET 7.0.0-preview.1.22076.8
Microsoft Reviewers: Open in CodeFlow

@ghost ghost assigned willibrandon Jan 29, 2022
@ghost ghost added the draft draft PR label Jan 30, 2022
…he target window and add support for drop description icons and text.

    *Narrow the scope to drop targets with support for drop icons and text.

    *Maintain the default DropTarget behavior with a last flag.

    *If the application specifies a DropIcon greather than DropIcon.Invalid (default), display the drag image, drop icon, and text specified in the DragEventArgs.

    *Add a DragDropHelper class to interface with the Shell's drag-image manager and provide methods to get and set the drop description.

    *Add a DragDrop functional test form to WinformsControlsTest with files for testing drag-and-drop operations.
Copy link
Member

@RussKie RussKie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@willibrandon

This comment was marked as outdated.

@azure-pipelines

This comment was marked as outdated.

@willibrandon willibrandon changed the title Add support for DropTarget drag images and drop descriptions Add support for drag images and drop descriptions Mar 10, 2022
Copy link
Contributor Author

@willibrandon willibrandon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Include the cursor offset.

@dreddy-work
Copy link
Member

@weltkante appreciate your feedback as well here. I think this will remove the need to expose interfaces publicly as discussed here: #457.

@willibrandon, We decided to take this forward and will work with you to get this ready for API review board.

@willibrandon
Copy link
Contributor Author

@willibrandon, We decided to take this forward and will work with you to get this ready for API review board.

I have one last part I'd like to include in this draft before taking it to the API review board and would like a chance to first get some feedback from the team. Specifically, specifying the drag image bitmap itself when calling DoDragDrop().

I'll try to get this last part pushed this evening. The only thing holding me up is I need to implement a function to copy an STGMEDIUM since I've previously been using CopyStgMedium() in Urlmon.lib and I don't think I'm able to use that function here. I should be able to implement it fairly easily using the OleDuplicateData function and will have some time to work on it this evening.

@weltkante
Copy link
Contributor

Thanks for the ping, looks promising, though I'm surprised this approach works considering WinForms doesn't implement SetData on its DataObject. I'll have a closer look at the proposed implementation and API over the next few days.

@willibrandon
Copy link
Contributor Author

willibrandon commented Mar 15, 2022

@weltkante - The IDataObject::SetData and IDataObject::GetData changes will be included in my next push, hopefully this evening.

@willibrandon
Copy link
Contributor Author

willibrandon commented Mar 16, 2022

@weltkante - I've pushed what I believe is the last major part required for this issue. Some further work needs to be done in order to add in the support for RichTextBox.OleCallback, ToolStripItem, and ToolStripDropTargetManager, but this is the gist of it. I am very interested in hearing what your thoughts are.

@willibrandon

This comment was marked as outdated.

-Check for null drag image bits
-Attempts to access shell objects from a multithreaded apartment fail with error E_NOINTERFACE.
-These are causing other tests to fail so they are going to detention.
@dreddy-work
Copy link
Member

I am moving this out of draft. @willibrandon , can you resolve conflict when you get chance. @JeremyKuhne Can you take a final look here.

@dreddy-work dreddy-work removed the draft draft PR label Jun 28, 2022
JeremyKuhne
JeremyKuhne previously approved these changes Jul 1, 2022
Copy link
Member

@JeremyKuhne JeremyKuhne left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! Thanks for all of your hard work and patience!

Copy link
Member

@JeremyKuhne JeremyKuhne left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved the conflict

@dreddy-work dreddy-work added the ready-to-merge PRs that are ready to merge but worth notifying the internal team. label Jul 1, 2022
@dreddy-work
Copy link
Member

@willibrandon, as FYI, this will be merged for the Preview 7 release.

@dreddy-work dreddy-work merged commit 5972c29 into dotnet:main Jul 5, 2022
@ghost ghost added this to the 7.0 Preview7 milestone Jul 5, 2022
@willibrandon
Copy link
Contributor Author

I'm seeing an AccessViolationException when drag-and-dropping to the RichTextBox, and the operation fails.

AccessViolationException

I'm not yet sure if this is related to the work done in this PR, or not.

@dreddy-work
Copy link
Member

@willibrandon , can you open a new issue for this and we can track the discussion there to figure out ?

dreddy-work pushed a commit that referenced this pull request Jul 7, 2022
* Allow drop targets to display a drag image while the cursor is over the target window and add support for drop description icons and text.

    *Narrow the scope to drop targets with support for drop icons and text.

    *Maintain the default DropTarget behavior with a last flag.

    *If the application specifies a DropIcon greather than DropIcon.Invalid (default), display the drag image, drop icon, and text specified in the DragEventArgs.

    *Add a DragDropHelper class to interface with the Shell's drag-image manager and provide methods to get and set the drop description.

    *Add a DragDrop functional test form to WinformsControlsTest with files for testing drag-and-drop operations.

* Tweak the drop description icon names.

* Cleanup feedback from RussKie

* Build fix

* Add IDragSourceHelper2 interface, SHDRAGIMAGE structure, and implement DragDropHelper.SetDragImage().

* Add the Control.DoDratgDrop API for specifying the drag image bitmap.
Add support for the drag-and-drop helper object calls to IDataObject::SetData and IDataObject::GetDataHere.

* Fix naming rule violation.

* Implement a CopyDragDropStgMedium function for copying drag-and-drop storage mediums.

* Remove unused DragDropHelper methods and add comments.

* Add CopyDragDropStgMedium format validation and comments.

* Hide the PictureBox default pointer on the test form.

* Cleanup feedback from RussKie.

* Tweak DragDropHelper return values.

* Fix the cursor from getting stuck and fix the cursor offset.

* Fix memory leak and add additional formats.

* Allow the application to specify the drag image bitmap via GivefeedbackEventArgs.

* Add more comments.

* Cleanup some feedback from welkante.
Implement change detection for drop descriptions in DragEnter and DragOver.
Make DragOver symmetrical in API with DragEnter.

* Reject SetData calls which have a non-NULL target device pointer.

* Add an internal drag and drop format class to hold related private formats and storage mediums.
Encapsulate the logic to copy the storage medium when retrieving the private formats.
Include a finalizer and call ReleaseStgMedium to free copied storage mediums marked for release.

* Handle when the caller retains ownership of the storage medium and make a copy.

* Reject incompatible storage medium types in IDataObject::SetData.

* Debug assert null target device pointer.

* Cleanup the return and let it fall through like previously.

* Add the Control.DoDragDrop API surface.
  -Optimize the drop description change detection in DropTarget.
  -Add drag image change detection in DropSource.
  -Set and get the DropTarget state to help support controls which have a complex internal structure.
  -Make DragEnter/DragOver more symmetrical.
  -Handle the DragOver edge case when a new drag image is specified in DropSource.GiveFeedback.
  -Handle the DragOver edge case when the previous DropTarget state was not DragEnter.

* Add the ToolStripItem.DoDragDrop API surface.
 -Add drag image and drop description support for ToolStrip.
 -Add a ToolStrip control to the test form for testing drag and drop operations.

* Add drag image and drop description support for RichTextBox.

* Add a RichTextBox demo to load DragAccept.rtf on DragDrop.

* Optimize drop description changes in DragLeave and Drop.

* Add a comment regarding IDataObject::GetData and when the Windows drag image manager requests formats that are not currently present in the data object.

* Improve the RichTextBox and ToolStrip demos.

* Add the InShellDragLoop format.

* Add data object support for CF_INDRAGLOOP.
 -Set the flag to true when setting the initial drag image.
 -Use the flag to check whether the data object is in a drag-and-drop loop.
 -Set the flag to false when the data has been dropped.

* Use Marshal.ReleaseComObject instead of Marshal.FinalReleaseComObject.

* Finish adding support CFSTR_INDRAGLOOP.

* Add support for dynamic addition of data during the drag loop through SetData.
 -Expand the scope of CopyDragDropStgMedium to copy all storage medium types and rename it to CopyStgMedium.

* Fix the timing of the flag.

* Clean up the comments and code.

* Free the DragDropFormat storage mediums after they are no longer in use.

* Fix the timing of the drag loop flag.

* Give the DragDropFormat appropriate method names.

* Set InDragLoop in GiveFeedback for good measure.

* Wrap the drag loop in a try finally and reset InDragLoop.

* Resolve nullable and mark members as static errors.

* Track the DropSource last target handle using IDropSourceNotify::DragEnterTarget

If a target has already been entered, call IDropTargetHelper::DragEnter to effectively display new drag images that are set during GiveFeedback.

* Cleanup feedback from dotnet api review

Align the names of DropImageType with Windows terminology including using the term Image over Icon.
 - Default -> Invalid
 - NoDropIcon -> NoImage

DragEventArgs
 - DropIcon -> DropImageType
 - Insert -> MessageReplacementToken
 - Mark the Message* properties as nullable.

GiveFeedbackEventArgs
 - Match DoDragDrop bitmap nullability and mark the bitmap non-nullable.

* Fix typo

* Check if the drop description values specified are valid

* Review feedback

* Review feedback

* Move CopyMedium to the DragDropFormat class and rename it to CopyData

* Remove unnecessary return and cleanup the demo

* Review feedback

* Update DropSource CCW to include support for IDropSourceNotify

* Review feedback

* Fix MessageReplacementToken conditional

* Be explicit about the entry indexes

* Review feedback

* Wrap the methods calls in a try/catch and return HResult of exception

* Remove the unnecessary checks in ToolStripDropTargetManager

* Simplify the checks in DropTarget

* Simplify the checks in RichTextBox.OleCallback

* Simplify the checks in DropSource

* Review feedback, first round

* Remove the unused using

* Better way of checking the incoming data object

* Have the designer generate the code

* Put the update drag image logic in its own method

* Review feedback

* Review feedback, second round

* Add the <returns> tag and describe the DragDropEffects return value

* Add GiveFeedbackEventArgs remarks

* Review feedback

* Review feedback and encapsulate the event argument equality logic

* Review feedback

* Fix duplicate symbols

* Review feedback

* Add DragDropFormat unit tests

* Supply named arguments for boolean parameters

* Cleanup the data source and variable name

* Add DragContext test data and generalize the tests

* Add DragDropHelper unit tests

* Skip test DragDropHelper_SetDragImage_ReturnsExptected

Results in Fatal error 0xC0000005 on Windows_x86 Debug and Release when executed from the command line.

* Add DragEventArgsTests for newly added properties

* Add GiveFeedbackEventArgs unit tests

* Add unit tests that verify thrown exceptions

* Add UI integration test for DragEnter

* Fix the fatal error on x86

* Tune up the test

* Unskip the skipped tests

* Fix the hard coded delay

* Fix SetDragImage tests

-Check for null drag image bits

* Review feedback

* Check for illegal cross-thread calls in DragDropHelper

-Attempts to access shell objects from a multithreaded apartment fail with error E_NOINTERFACE.

* Skip the problem tests

-These are causing other tests to fail so they are going to detention.

* Drag two items in the UI test

Co-authored-by: Jeremy Kuhne <[email protected]>
dreddy-work pushed a commit that referenced this pull request Jul 7, 2022
* Allow drop targets to display a drag image while the cursor is over the target window and add support for drop description icons and text.

    *Narrow the scope to drop targets with support for drop icons and text.

    *Maintain the default DropTarget behavior with a last flag.

    *If the application specifies a DropIcon greather than DropIcon.Invalid (default), display the drag image, drop icon, and text specified in the DragEventArgs.

    *Add a DragDropHelper class to interface with the Shell's drag-image manager and provide methods to get and set the drop description.

    *Add a DragDrop functional test form to WinformsControlsTest with files for testing drag-and-drop operations.

* Tweak the drop description icon names.

* Cleanup feedback from RussKie

* Build fix

* Add IDragSourceHelper2 interface, SHDRAGIMAGE structure, and implement DragDropHelper.SetDragImage().

* Add the Control.DoDratgDrop API for specifying the drag image bitmap.
Add support for the drag-and-drop helper object calls to IDataObject::SetData and IDataObject::GetDataHere.

* Fix naming rule violation.

* Implement a CopyDragDropStgMedium function for copying drag-and-drop storage mediums.

* Remove unused DragDropHelper methods and add comments.

* Add CopyDragDropStgMedium format validation and comments.

* Hide the PictureBox default pointer on the test form.

* Cleanup feedback from RussKie.

* Tweak DragDropHelper return values.

* Fix the cursor from getting stuck and fix the cursor offset.

* Fix memory leak and add additional formats.

* Allow the application to specify the drag image bitmap via GivefeedbackEventArgs.

* Add more comments.

* Cleanup some feedback from welkante.
Implement change detection for drop descriptions in DragEnter and DragOver.
Make DragOver symmetrical in API with DragEnter.

* Reject SetData calls which have a non-NULL target device pointer.

* Add an internal drag and drop format class to hold related private formats and storage mediums.
Encapsulate the logic to copy the storage medium when retrieving the private formats.
Include a finalizer and call ReleaseStgMedium to free copied storage mediums marked for release.

* Handle when the caller retains ownership of the storage medium and make a copy.

* Reject incompatible storage medium types in IDataObject::SetData.

* Debug assert null target device pointer.

* Cleanup the return and let it fall through like previously.

* Add the Control.DoDragDrop API surface.
  -Optimize the drop description change detection in DropTarget.
  -Add drag image change detection in DropSource.
  -Set and get the DropTarget state to help support controls which have a complex internal structure.
  -Make DragEnter/DragOver more symmetrical.
  -Handle the DragOver edge case when a new drag image is specified in DropSource.GiveFeedback.
  -Handle the DragOver edge case when the previous DropTarget state was not DragEnter.

* Add the ToolStripItem.DoDragDrop API surface.
 -Add drag image and drop description support for ToolStrip.
 -Add a ToolStrip control to the test form for testing drag and drop operations.

* Add drag image and drop description support for RichTextBox.

* Add a RichTextBox demo to load DragAccept.rtf on DragDrop.

* Optimize drop description changes in DragLeave and Drop.

* Add a comment regarding IDataObject::GetData and when the Windows drag image manager requests formats that are not currently present in the data object.

* Improve the RichTextBox and ToolStrip demos.

* Add the InShellDragLoop format.

* Add data object support for CF_INDRAGLOOP.
 -Set the flag to true when setting the initial drag image.
 -Use the flag to check whether the data object is in a drag-and-drop loop.
 -Set the flag to false when the data has been dropped.

* Use Marshal.ReleaseComObject instead of Marshal.FinalReleaseComObject.

* Finish adding support CFSTR_INDRAGLOOP.

* Add support for dynamic addition of data during the drag loop through SetData.
 -Expand the scope of CopyDragDropStgMedium to copy all storage medium types and rename it to CopyStgMedium.

* Fix the timing of the flag.

* Clean up the comments and code.

* Free the DragDropFormat storage mediums after they are no longer in use.

* Fix the timing of the drag loop flag.

* Give the DragDropFormat appropriate method names.

* Set InDragLoop in GiveFeedback for good measure.

* Wrap the drag loop in a try finally and reset InDragLoop.

* Resolve nullable and mark members as static errors.

* Track the DropSource last target handle using IDropSourceNotify::DragEnterTarget

If a target has already been entered, call IDropTargetHelper::DragEnter to effectively display new drag images that are set during GiveFeedback.

* Cleanup feedback from dotnet api review

Align the names of DropImageType with Windows terminology including using the term Image over Icon.
 - Default -> Invalid
 - NoDropIcon -> NoImage

DragEventArgs
 - DropIcon -> DropImageType
 - Insert -> MessageReplacementToken
 - Mark the Message* properties as nullable.

GiveFeedbackEventArgs
 - Match DoDragDrop bitmap nullability and mark the bitmap non-nullable.

* Fix typo

* Check if the drop description values specified are valid

* Review feedback

* Review feedback

* Move CopyMedium to the DragDropFormat class and rename it to CopyData

* Remove unnecessary return and cleanup the demo

* Review feedback

* Update DropSource CCW to include support for IDropSourceNotify

* Review feedback

* Fix MessageReplacementToken conditional

* Be explicit about the entry indexes

* Review feedback

* Wrap the methods calls in a try/catch and return HResult of exception

* Remove the unnecessary checks in ToolStripDropTargetManager

* Simplify the checks in DropTarget

* Simplify the checks in RichTextBox.OleCallback

* Simplify the checks in DropSource

* Review feedback, first round

* Remove the unused using

* Better way of checking the incoming data object

* Have the designer generate the code

* Put the update drag image logic in its own method

* Review feedback

* Review feedback, second round

* Add the <returns> tag and describe the DragDropEffects return value

* Add GiveFeedbackEventArgs remarks

* Review feedback

* Review feedback and encapsulate the event argument equality logic

* Review feedback

* Fix duplicate symbols

* Review feedback

* Add DragDropFormat unit tests

* Supply named arguments for boolean parameters

* Cleanup the data source and variable name

* Add DragContext test data and generalize the tests

* Add DragDropHelper unit tests

* Skip test DragDropHelper_SetDragImage_ReturnsExptected

Results in Fatal error 0xC0000005 on Windows_x86 Debug and Release when executed from the command line.

* Add DragEventArgsTests for newly added properties

* Add GiveFeedbackEventArgs unit tests

* Add unit tests that verify thrown exceptions

* Add UI integration test for DragEnter

* Fix the fatal error on x86

* Tune up the test

* Unskip the skipped tests

* Fix the hard coded delay

* Fix SetDragImage tests

-Check for null drag image bits

* Review feedback

* Check for illegal cross-thread calls in DragDropHelper

-Attempts to access shell objects from a multithreaded apartment fail with error E_NOINTERFACE.

* Skip the problem tests

-These are causing other tests to fail so they are going to detention.

* Drag two items in the UI test

Co-authored-by: Jeremy Kuhne <[email protected]>
@willibrandon
Copy link
Contributor Author

Before I forget, thank you for the opportunity to work on this. It has been an incredible learning experience for me and everyone here has been so helpful and welcoming. Early on I was terrified that I wouldn’t be able to figure this one out. While getting the drag images from Explorer to display on WinForms drop targets was trivial, specifying the drag image bitmap itself from a drag source was a much more daunting task for me. When I got it working the first time I almost had a heart attack and started screaming OMG. This has been an awesome experience for me, thank you.

@kant2002
Copy link
Contributor

kant2002 commented Jul 8, 2022

Congratulation! That’s WinForms team for you 🏅. Also, take care of your heart ;)

@RussKie
Copy link
Member

RussKie commented Jul 18, 2022

Thank you so much for your efforts and your patience!

@RussKie RussKie removed the ready-to-merge PRs that are ready to merge but worth notifying the internal team. label Jul 18, 2022
@ghost ghost locked as resolved and limited conversation to collaborators Aug 24, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

support drag and drop with icon and text label
7 participants