Describe the bug
Given a TreeView in multi-select mode, a drag and drop operation for an unselected item should not drag and drop the selected items. Here are two examples showcasing the current behavior:
Both examples look like bugs to me. I think a much more natural drag & drop operation logic would be the following:
Expected behavior
As written above, I would like to see dragging and dropping an unselected item to only move that one item, and not drop selected items as well. Dragging a selected item, however, should drag all selected items as a group (as is the case today).
Version Info
NuGet package version:
WinUI 2.4 and WinUI 2.5 previews
| Windows 10 version | Saw the problem? |
| :--------------------------------- | :-------------------- |
| Insider Build (xxxxx) | |
| May 2020 Update (19041) | Yes |
| November 2019 Update (18363) | |
| May 2019 Update (18362) | |
| October 2018 Update (17763) | |
| April 2018 Update (17134) | |
| Fall Creators Update (16299) | |
| Creators Update (15063) | |
| Device form factor | Saw the problem? |
| :----------------- | :--------------- |
| Desktop | Yes |
| Xbox | |
| Surface Hub | |
| IoT | |
@predavid-zz FYI. @Felix-Dev I agree with your Expected Behavior
Open question: How should this work with non leaf nodes for all 3 selection states, unslected, partially selected (some, not all children selected), and selected.
@StephenLPeters Below are my initial thoughts.
If a non-leaf node is started to be dragged while being
I think we should keep that behavior as it is the same behavior we are seeing today when dragging a selected leaf node: Here, all selected items will take part again in the drag & drop operation. Keeping that behavior for selected non-leaf nodes will provide a consistent behavior when dragging a selected node.
I think we should change that behavior to drag and drop only the selected items which are children of the partially selected item. Selected items which are not children of the partially selected item should not take part in the drag & drop operation.
I think we should keep the current behavior.
(I did not make any gifs of the current behaviors described above but you can easily check them in the XAML Control Gallery's TreeView page.)
The Selected and Unselected cases make sense to me. I'm not sure about the Partially Selected case and would like to get some other people in the discussion. @YuliKl @predavid-zz @ranjeshj
@StephenLPeters Would you currently be inclined to keep the existing behavior when dragging a partially selected node (and if so, why?) or do you have another possible suggestion?
I think there are a number of behaviors I could be convinced make sense; Treat it the same as the selected case, treat it the same as the unselected case, your suggestion, blocking drag and drop in this scenario. I'm not confident I understand the space well enough to accurately choose the best solution.
@StephenLPeters I am starting to like the suggestion of actually blocking drag and drop for partially selected nodes. One reason being that if you drag such a node, the drag visual indicates you can actually drag and drop this node into a new position inside the TreeView. While this is indeed the case for selected and unselected dragged nodes, this is not the case for partially selected nodes! A partially selected node today *cannot be dropped into a different position, no matter what its drag visual might suggest.
As such, blocking drag and drop for partially selected nodes sounds quite compelling to me. Especially as no drag and drop functionality existing today would actually be lost here.
I am not a fan of the partial selection blocks drag and drop idea. In selectionmode multiple, you would end up with a scenario where you aren't able to drag and drop a lot of child node.
In addition to that, I also find the current completely selected case a bit strange. What if I just want to drag and drop the children of a node? Do I really have to drag and drop one by one then? I think dragging and dropping should depend on where the drag and drop started, if I started a child node, only drag the child nodes, if I drag a parent node, move the whole subtree.
I am not a fan of the partial selection blocks drag and drop idea. In selectionmode multiple, you would end up with a scenario where you aren't able to drag and drop a lot of child node.
In addition to that, I also find the current completely selected case a bit strange. What if I just want to drag and drop the children of a node? Do I really have to drag and drop one by one then? I think dragging and dropping should depend on where the drag and drop started, if I started a child node, only drag the child nodes, if I drag a parent node, move the whole subtree.
Hmm, I think another reasonable solutions is that dragging a non-leaf node always drags it and all its children, regardless of selection state. Is this behavior that we could see apps wanting to customize? What if selection is managed by the app (not the user) but they still want drag and drop, then it wouldn't be possible for the user to rearrange the selected items.
What if I just want to drag and drop the children of a node? Do I really have to drag and drop one by one then?
WIth the current behavior, if you want to drag the children of a node, you just need to select them all and then start a drag operation. So that's definitely possible today.
I kinda like the current behavior when dragging a selected node. This allows me to do something like this:
Hmm, I think another reasonable solutions is that dragging a non-leaf node always drags it and all its children, regardless of selection state.
That's also a possibility.
Is this behavior that we could see apps wanting to customize?
I think there will scenarios where apps might want to ask for just that.
For partially selected this works (though your proposed solution to block drag and drop for partial selection would break that).
I was asking about a node where I want ALL of the children, but not the parent node. Currently, that would drag and drop both the children, and the parent of those items.
(though your proposed solution to block drag and drop for partial selection would break that)
I did not propose that as a solution :) Also I'm not sure why it would break that, because one of the ideas thrown into the ring here by @StephenLPeters originally was to block only dragging of the partially selected node. With that idea I could still drag and drop its children like shown in the gif above.
That said, dragging all of the children of a node currently isn't possible without dragging the parent node as well, as you pointed out. This should be supported though.
If we look at the File Explorer as an example, we see dragging and dropping works like this there:
So, we could decide to copy file explorer's behavior here. I think this would mean if I start dragging a selected node, all other selected nodes with the same direct parent will be included in a drag operation (including their children). That way, I can easily drag and drop all the children of a node - and only them. If I want to drag all the children and their parent node as well - and only them - I have to make sure no sibling of the parent node is selected as well (sibling here is a different node which has the same node parent of our dragged node). This could perhaps be a bit too complicated as a default behavior, not sure here.
This would also mean the behavior shown in my gif above would no longer be possible but that is something I could live with.
Since dragging an unselected non leaf node includes all of its children given the current behavior, I guess we could use the same behavior when starting to drag a partially selected non-leaf node: All of its children will be included as well, so only the parent and its children will be included in the drag operation, no matter if other nodes are selected somewhere..
Oh sorry, must have misunderstood you regarding the blocking of drag and drop.
Regarding the fully selection mode, there is the following issue I see: What happens when I drag the children of Home remodel in this screenshot?
Should it drag and drop only "Paint Color Scheme" and "Flooring woodgrain type"? Or should it drag all selected nodes? What if all items of "home remodel" are selected?
The issue here might be that a good drag and drop solution would require us here that you are able to select all children of a node without selecting said node. Current behavior is that a nodes selection state is defined by its children if it has children. Maybe this is not the most intuitive behavior though, for example I can select all files in a folder, yet that doesn't mean I also meant to select that folder.
What happens when I drag the children of Home remodel in this screenshot? Should it drag and drop only "Paint Color Scheme" and "Flooring woodgrain type"? Or should it drag all selected nodes?
If I strictly apply the specific File Explorer behavior shown in the gif above, I think only "Paint Color Scheme" and "Flooring woodgrain type" would be dragged. So the other selected nodes like "Overall Project Plan" wouldn't be included.
What if all items of "home remodel" are selected?
In that case, dragging one of its children will include all four of its children (and only them) in the drag and drop operation.
Now, if I were to drag one of the selected children of "Work Documents" only its three selected children would be included, the selected children of "Home Remodel" would not be included (as they don't share the same parent node). In other words, I can no longer just select nodes here and there and them have them all included in a drag and drop operation as shown in the gif above.
I could live with that though as I find the ability to be able to drag all chidren of a node - and only them - as much more important. After all, that's not possible with today's behavior at all whereas with the matching File Explorer suggestion I could still drag both the children of "Home Remodel" and "Work Documents", albeit in two different drag and drop operations.
But wouldn't make that selection a bit unpredictable? In some cases, you drag all items, in other cases you only drag a few items and currently, you might drag more than you expected to.
Maybe we should drag all items that are selected, however selecting all children of a node shouldn't select that node?
But wouldn't make that selection a bit unpredictable? In some cases, you drag all items, in other cases you only drag a few items and currently, you might drag more than you expected to.
Yes, I am seeing that as well.
(Ok, watching Bayern - Barca now, so limited attention from me for now 馃槄)
@chingucoding @StephenLPeters
I have summarized the current most promising ideas being floated around in this issue below. My hope is this will help push this issue forward until it is ready to be implemented.
I think pretty much agreed upon is the suggested updated drag & drop behavior of an unselected node. Here it is:
| Selection state | leaf node | parent node |
|---|---|---|
| Unselected | Dragging an unselected leaf node will only drag this one node. | Dragging an unselected parent node will additionally include all its child nodes in the drag & drop operation. |
It is getting a bit trickier when we are looking at the desired drag & drop experience when the node initiating the drag is (partially) selected:
One of the major underlying problems with today's in-built drag & drop experience of selected TreeView nodes is that it is currently impossible to drag all children of a node in a single drag & drop operation without also including their parent node. Here's why:
As a result, if I want to drag all children of a node in a single drag & drop operation, I first have to select them all - but selecting all child nodes will also automaticall select their parent node! As such, the parent node will be included in any drag & operation.
We have seen two possible approaches being outlined/suggested so far here which will enable the scenario of dragging only the children of a node in a single drag & drop operation, and not its parent node.
The first suggestion is to change the drag & drop experience when being initiated on a selected node. The idea here is that the drag & drop experience of a selected node will now be context based. More precisely, the nodes included in drag & drop operation will now be dependent on the position of the selected node (initiating the drag) in the TreeView. No longer will all selected nodes in the TreeView be included automatically, no matter which selected node is used to initiate the drag operation. See below for a table with the suggested updated behavior:
| Selection state | leaf node | parent node |
|---|---|---|
| Partially selected | - | Dragging a partially selected parent node will mirror the drag & drop experience when dragging an unselected parent node: All its children (selected or not) will additionally be included the drag & drop operation. No other selected nodes will be included here. |
| Selected | Dragging a selected leaf node will include all selected nodes (including their children, if any) in the drag & drop operation which have the same immediate parent node as the dragged selected node. (This mimics the drag & drop experience in the Windows File Explorer today.) | Dragging a selected parent node will include all its child nodes (and their children, if any) and all selected nodes which have the same immediate parent node as the dragged selected node. |
Consequently, no longer will all selected nodes be included in the drag & drop operation, no matter on which selected node the drag operation is initiated. See the following drag & drop operation possible today:
As you can see, in a single drag & drop operation, all selected nodes were moved. With the poposed changes above, this would no longer be possible in a single drag & drop operation but would require three drag & drop operations instead (one for each selected node).
The drag & drop experience outlined above features two major characteristics:
These characteristcs ensure this proposed drag & drop experience is consistent in itself and als familiar to Windows users.
A possible alternative has been suggested by @chingucoding. It does not feature a context based drag & drop experience for selected nodes like the first suggestion. Instead, it proposes a change to the in-built TreeView selection logic to address the major shortcoming of the current drag & drop experience when dragging a selected node:
Selecting all children of a node will no longer automatically select their parent node.
In other words, even though dragging a selected node will still actually drag all selected nodes in a TreeView, since all child nodes can be selected without automatically selecting their parent node, this solves the major shortcomming of today's TreeView drag & drop experience just as suggestion 1 does.
The underlying idea with this suggestion is that the current in-built selection logic of the TreeView might not always be desirable. Consider, for example, a TreeView control used in a file explorer context: Selecting all files (the child nodes) of a folder (their parent node) should probably not automatically select the folder as well. This would be the case with the current implementation though. Instead, if the folder (the parent node) should be selected, then it should have to be selected manually.
A few open questions here, @chingucoding:
I have outlined the two most promising suggestions developed in this thread so far above. Both suggestions solve the current major design flaw in today's TreeView drag & drop experience - namely that it is not possible to drag & drop all the selected children of a node without also including that parent node in a drag & drop operation.
Suggestion 1 keeps the current in-built selection logic unchanged (so selecting all child nodes will also automatically select their parent node) while introducing a position-based drag & drop experience.
Suggestion 2 keeps the current drag & drop experience for selected nodes unchanged (dragging a selected node will always drag all selected node) but makes a change to the current selection logic of the TreeView (no longer would a parent node be automatically selected when all its child nodes are selected).
@chingucoding @StephenLPeters Apologizing for the lengthy post but I think it will help move this discussion forward as needed.
Thank you for the detailed post @Felix-Dev !
What would be the selection state of a node whose children are all selected? It could be partially selected to indicate that all of its children are selected but the node itself is not. While this will keep the current system of three different selection states a node can have, it will expand today's definition of a partially selected node. That might not be a problem though because the concept of partially selected nodes only exists in internal WinUI APIs, and the public API surface only states whether a node is selected or unselected (a partially sected node is exposed as a unselected node to the public).
I would say it is partially selected since its tree is not entirely unselected, however its entire subtree isn't selected either. So neither unselected nor selected are entirely true, leaving us with partially selected. Unfortunately though, this would be a (major) breaking change if I am not mistaken.
How would you design the drag & drop experience of partially selected nodes? The same as outlined in suggestion 1 or differently?
Same as an unselected node, drag and drop the node and it's childern. So for drag and drop it would be treated as unselected. Only when dragging a selected item, we drag all selected item and actually ignore the starting position of the selected item.
Same as an unselected node, drag and drop the node and it's childern. So for drag and drop it would be treated as unselected. Only when dragging a selected item, we drag all selected item and actually ignore the starting position of the selected item.
@chingucoding So the same as suggestion 1 then. This means the two suggestions will only differ in how a drag & drop operation looks like for selected nodes.
@StephenLPeters To comment on when a change to the in-built selection logic of the TreeView would be a feasible change - if it should be done.
I think that both solutions make sense to me, however I think I slightly prefer suggestion 2 as it seems simpler and easier for the user to understand how it works. And I agree with marcel, all children selected means the parent is partially selected. @chingucoding can we flesh out why this is a breaking change? I see some niche cases that would potentially change behavior but not ones that would cause crashes.
@predavid-zz FYI
I don't think changing the in-built selection logic would lead to app crashes (and also no compilation crashes). What would be the case is that developers today relying on the selection logic that selecting all the children of a node also selects their parent would need to adapt to the changed behavior. Is that a major concern? I'm not sure here (missing data).
This wouldn't be a breaking change in the sense that existing code crashed or fails to compile. However some apps might have this assumption that if all child nodes are selected, that the parent is selected. In some cases, this might result in a lot of nodes being marked as selected despite only the leaves of the tree being selected.
If we now mark the parent as partially selected, we would break this assumption that some developers might have. But I think, in this case it is more important that the logic is more natural to the end user which suggestion 2 is in my opinion.
Cool, that is what I think as well, just wanted to make sure I wasn't overlooking something.
I am preferring suggestion 2 as well as the solution moving forward. Only child nodes should be automatically selected if their parent node is selected. Other nodes (like a parent node of child nodes) should require manual selection. As suggested by all three of us, a parent node with all its children selected, but which isn't selected itself, should be displayed as a partially selected node.
I'm going to ask some other members of the team to weigh in here as well, I don't feel like I can unilaterally decide this, but I'll report back soon.
@StephenLPeters Did you find some time to discuss this with other members of the team?
Most helpful comment
Yes, I am seeing that as well.
(Ok, watching Bayern - Barca now, so limited attention from me for now 馃槄)