Two failure modes that both showed the user the "no" cursor with no
other feedback:
1. ResolveDropTarget returned null when e.Source had no
SharpTreeViewItem ancestor, so Explorer drops landing in the gap
beneath the last row (or onto an empty list) never reached
SharpTreeNode.InternalDrop.
2. The middle 50% of a row produces a DropPlace.Inside target on the
row's own node. Most concrete SharpTreeNodes inherit the base CanDrop
(returns false), so a literal "drop a .dll onto an assembly row"
refused even though AssemblyListTreeNode happily accepts that payload.
For (1), fall back to (Root, Children.Count, DropPlace.Inside) when no
row is hit. For (2), introduce PickAcceptingTarget which retries with
the empty-space (root) target when the initial CanDrop is false. Both
OnDragOver and OnDrop go through the same picker so the cursor and the
actual drop agree on the outcome. The retry skips when the initial
target already IS the root, so a real refusal still surfaces as "no".
The marker adorner stays hidden for empty-space drops because the
place is always Inside (Item is null for that case); the existing
DropPlace.Inside early return covers it.
DropTarget, DropPlace, and the two new helpers are internal-visible to
the ILSpy.Tests project for the unit tests that assert the fallback
chain.
Assisted-by: Claude:claude-opus-4-7[1m]:Claude Code