-
Notifications
You must be signed in to change notification settings - Fork 711
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
Question: How to block a drop using the DragOver event in TreeView or TreeViewItem? #1154
Comments
@dpaulino I tried a few things looks like the easiest way to do this is updating private void TreeView_DragItemsStarting(Microsoft.UI.Xaml.Controls.TreeView sender, Microsoft.UI.Xaml.Controls.TreeViewDragItemsStartingEventArgs args)
{
YourTreeView.CanReorderItems = /*isItemDraggable*/;
} |
If I were to use the drag items starting event, do I have knowledge of what the drop target is going to be? I would need to know the drop target in order to decide if the drop should be blocked, right? To clarify my question, here are some scenarios. Given a tree that looks like this
You can see that in scenario 4, I would need to block the drop. This is where I would like to use the drag over event. When the user picks up group 2 and hovers it over leaf b, I want the tree view to show the 🚫 icon to express that this drop operation is not allowed. Does the drag items started event work in this scenario? |
I see, I think you can move the logic to DragOver in this case private void TreeViewItem_DragOver(object sender, DragEventArgs e)
{
TreeViewItem treeViewItem = sender as TreeViewItem;
var item = YourTreeView.ItemFromContainer(treeViewItem) as YourItemType;
TestTreeView.CanReorderItems = item.IsGroup;
} The RequestedOperation and AcceptedOperation didn't really work because TreeView is changing those values internally when CanReorderItems is true, you can take a look at the code and see what's its doing, but setting the value to false should block the reorder/drop completely. |
Not sure if you deleted your previous comment but I got an email asking about the sender parameter...
Sender should be the item you are currently hovering over.
Try adding the following code to your TreeViewTest project and you should be able to drag "first" into "second" but not vice versa.
private void TreeViewItem_DragOver(object sender, DragEventArgs e)
{
MUXC.TreeViewItem treeViewItem = sender as MUXC.TreeViewItem;
var item = TestTreeView.ItemFromContainer(treeViewItem) as ExplorerItem;
TestTreeView.CanReorderItems = item.Name.Equals("second");
}
…________________________________
From: Daniel Paulino <notifications@github.com>
Sent: Wednesday, August 14, 2019 7:18 PM
To: microsoft/microsoft-ui-xaml <microsoft-ui-xaml@noreply.github.com>
Cc: Kai Guo <Guo.Kai@microsoft.com>; Assign <assign@noreply.github.com>
Subject: Re: [microsoft/microsoft-ui-xaml] Question: How to block a drop using the DragOver event in TreeView or TreeViewItem? (#1154)
I just tried your suggestion, but I realize there's something missing. The DragOver event does not seem to contain information about the target item that we are hovering over.
I need to be able to determine the target item in order to decide whether or not I should allow or disallow the drop.
In your previous comment, the item variable comes from the sender parameter. But it seems that sender represents the item being dragged, not the item we are hovering over.
How can I determine the target item while reordering items in the WinUI TreeView?
—
You are receiving this because you were assigned.
Reply to this email directly, view it on GitHub<https://nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fmicrosoft%2Fmicrosoft-ui-xaml%2Fissues%2F1154%3Femail_source%3Dnotifications%26email_token%3DABBYFCQQZKLZJQXKVTSMNV3QES4JFA5CNFSM4IK3BVCKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD4KUU7Q%23issuecomment-521489022&data=02%7C01%7CGuo.Kai%40microsoft.com%7C21c0a8e7565a4434d2ef08d72126ef33%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637014323409254610&sdata=RdeI4F9sgF2G1iOo5nIUdpRbPziN%2BaLpRKSm5P32ewI%3D&reserved=0>, or mute the thread<https://nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fnotifications%2Funsubscribe-auth%2FABBYFCXGKMN6VJUIYYDWMDDQES4JFANCNFSM4IK3BVCA&data=02%7C01%7CGuo.Kai%40microsoft.com%7C21c0a8e7565a4434d2ef08d72126ef33%7C72f988bf86f141af91ab2d7cd011db47%7C1%7C0%7C637014323409264604&sdata=tZ6QXh5%2ByN4qxUVDBDBdMpdafo4ZfSnc5xzDej46uXA%3D&reserved=0>.
|
I deleted my previous comment because I found out I was doing something wrong. But now I'm back with a new comment. I have tried this approach: private void TreeViewItem_DragOver(object sender, DragEventArgs e)
{
TreeViewItem treeViewItem = sender as TreeViewItem;
var item = YourTreeView.ItemFromContainer(treeViewItem) as YourItemType;
TestTreeView.CanReorderItems = item.IsGroup;
} It sort of works, but it seems I am no longer able to reorder the list. Example below. Say I have a tree that looks like this:
Using the approach you provided, I am unable to move Leaf 1 to between Leaf 2 and 3. The reason seems to be that in the DragOver event, the Any ideas on how to allow reordering but still keep all the previous requirements? Also, is there a fully functional drag drop sample with conditional dropping somewhere? That would make things a lot easier if someone could just make a fully functional sample for a TreeView that can perform conditional dropping. |
Try setting CanReorderItems back to true in private void TreeViewItem_DragLeave(object sender, DragEventArgs e)
{
TestTreeView.CanReorderItems = true;
} |
Hmm, looks like that doesn't work. You might have to override those drag&drop functions and handle everything on your own. Let me double check tomorrow and see if there are better alternatives... |
Yeah I have tried that and it does not work. Would you or someone else be able to build a small sample that uses the TreeView with ItemsSource bound to an ObservableCollection and with conditional drop? I've been trying to make this work for 3 months and I have just had so many problems. I'm desperate to have this ability because my customers have been complaining so much about this. |
I made a sample app here: https://github.com/kaiguo/TreeViewConditionalReorderSample Updating AcceptedOperation in event callbacks doesn't work because the handler is triggered after the actual event and TreeViewItem has already done a bunch of stuff when you get to the callback. But overriding the events in TreeViewItem does work since you get a chance to make changes before TreeViewItem executing its own code. |
This sample looks promising. I just tried it and I got a crash while performing a drag. However, I can no longer reproduce it... I'm going to experiment with this a bit more and I will report back if I can isolate the crash. |
Hmm. When I perform a drop onto a group, the observable collection is not being updated. Can you confirm? |
Looks like it's working for me. I added a button in the sample app to dump out ItemsSource, you can take a look. |
Ah I see what's going on. Your sample is using the prerelease package. When I reverted your sample to the regular release package, the observable collection was not being updated. So that bug was fixed in the prerelease package. Let me try updating my app to the prerelease package and I'll try this again. |
Weird, I'm getting a C++ exception on startup after I updated to that prerelease package. Here's the tail end of the debug output
The error seems to be: |
Weird. I seem to have fixed it by cleaning the solution and then rebuilding. The observable collection is being updated now. Going to do a few more tests before I close this issue. |
Looks good. Closing issue. Thanks for all your help. |
@kaiguo I just found a crash and it's due to a requirement that I incorrectly stated at the start of this issue: groups cannot actually contain other groups. The crash occurs when I have something looking like this:
If I drag group 1 to hover in the space between group 2 and leaf a, a drop is allowed and it will lead to a crash for my app due to an invalid cast. In my scenario, the invalid cast is correct because groups cannot contain other groups. How could the sample you provided be modified to support this scenario? |
@kaiguo friendly ping. Any thoughts on my previous comment? |
We probably need some new APIs for this to get the drop position. As a workaround for now, I think you can use InsertionPanel to get the item above/below the dropping position, which should help you figure out whether the drop is valid or not (e.g. block the drop if dragged item is a group, and the item above or its parent is a group). I put something here to show you how to get the above/below item by using InsertionPanel. |
I'll try this out and report back soon. I appreciate your help. |
@lukasf thanks for referencing that proposal. I would like to see this feature added ASAP though rather than wait for WinUI 3.0. My customers have been demanding proper drag and drop abilities for the past 4 months, and I cannot implement it properly due to this treeview limitation. WinUI team, please consider addressing this as soon as possible. |
Just to throw my support onto this as well. I raised #381 a while ago. The drag and drop APIs feel very incomplete and inflexible. Do we have an ETA on support for this? It's something I'm hearing the need for a lot, as well. |
I'm on some other lifted XAML work but I'll try and see if I can add something in 2.3 release (no guarantee😅). |
@kaiguo that would be awesome. I think I have the same issue (in #381) as @dpaulino, I want to be able to enforce the order of items (I.e. have pinned items at the top of the tree view) and block moving certain items and make certain items not be drop targets. Thanks! |
@dpaulino I updated the sample app to use the latest TreeView changes, I think this should solve the issue you mentioned in this comment. |
Thanks for the update. Is this available in a prerelease package that I could try out? |
Yeah, you can find the prerelease package in the sample app here. |
Small question on this topic. Is this change approved for stable releases? Wasnt able to work with the sample app provided on this topic. |
I think the change should be in the latest (pre)release version of WinUI. |
Well, the latest pre-release i found is 2.4.0-prerelease.200506001 where there is a 2.4.0 stable release. The topic was opened on an 2.3 and i'm still missing the "NewParent" property on TreeViewDragItemsCompletedEventArgs |
The "NewParent" property is still marked as preview, so it currently should only be available in prereleases. |
as said, i tested with several 2.4 pre releases, an wasn't able to access it |
It was renamed with #1692, the property is called "NewParentItem" now. Sorry about the confusion. |
Namingconversion are no problem in general... but, i cant find any. There are only two acessable properties, Items and DropResult. Call me dumb, but i'm not able to get a working solution. |
I've updated the linked project from @kaiguo to use the newest prerelease. Can you clone the following project and check if it compiles for you? The updated sample: https://github.com/chingucoding/TreeViewConditionalReorderSample |
Yes, it does and works like a charme. Well, obivously i missed out my usings... |
Glad to hear that we found the issue, happy that I could help you :) |
@chingucoding the link above is broken, can you say where the repo has gone? |
I'm afraid I've deleted as part of repo cleanups throughout the years @sjb-sjb. Is blocking dropping a TreeViewItem something you need guidance with? |
@chingucoding Yes please, thanks for offering! I understand the general point that one can control reordering locally by setting TreeView.CanReorderItems from within the OnDragEnter and other callbacks of TreeViewItem. I also see that one must set AllowDrop = true on all of the TreeViewItems in order to allow the callbacks to be invoked in the first place (and incidentally these callbacks replace PointerEntered / PointerExited). Also, if one does not want to allow reordering a dragged item so that it is outside of a given folder, then one must avoid setting TreeView.CanReorderItems if the drag pointer is above the folder rather than within or below the folder. Overall the results are OK except for a visual problem. When an item moves to allow reordering, it can double up on the item that is being dragged. In the attached picture, L1 is being dragged down below L2. L2 has moved up to the spot where L1 previously was. But we can still see L1 behind L2. If we release the mouse button over G, then L1 is not dropped into G (this is correct) but L2 remains visually superimposed on L1. However when a refresh occurs then the two leaves L1, L2 appear in their correct places underneath F, first L1 then L2 below it. What I am not sure of is whether this is a bug or whether there is something additional that should be done in the overrides to prevent this. Thoughts? I have a reference to the TreeView within my derived TreeViewItem and my item type is TreeEntity which contains flags CanDrop/CanReorder indicating the desired droppability / reorderability. The overrides are as follows:
I have attached a sample project using WinUI 3. |
A less serious problem is that this approach does not always detect when a reorder is appropriate. Specifically in the scenario above, reordering can occur within the F subtree but not the G subtree. If we drag L1 down to G then TreeView.CanReorderItems is correctly set to false; then when we drag it back up into the blank space above G but below the superimposed L1/L2, it does not detect that a reorder can occur there. It will not re-enable TreeView.CanReorderItems until we drag it back up to the superimposed L1/L2, at which point a DragEnter in L2 is detected and the TreeView reordering is re-enabled. There does not seem to be any event that fires while dragging over the blank space after entering and leaving G. While we were dragging L1 down below L2, but before entering G, the ability to reorder below L2 was detected. |
Sorry for the delayed response @sjb-sjb. The project you shared seems fine, I also used the same approach back then (hence I haven't attached a new project showcasing that). My guess would be this is an issue with the control though the code you shared seems quite complicated. Is your intention to adjust where the position of items should be to reorder, hence the height calculations? |
I have a TreeView that contains two types of tree items,
Leaf
andGroup
.Leaves can be children of groups.
Groups can be children of groups.
Leaves cannot have children.
Within the same tree, I want to allow my customers to reorder the tree and to move items to different groups by dragging and dropping elements. Based on the rules provided above, I need to be able to conditionally block certain drop operations, and I want to block them during the DragOver event. I have tried the following code, but it does nothing to block the drop:
Am I doing something wrong? Can someone show me how to conditionally block a drop operation?
The text was updated successfully, but these errors were encountered: