Drag and Drop in Q2 2014

4 posts, 0 answers
  1. Sergio Graziosi
    Sergio Graziosi avatar
    4 posts
    Member since:
    Apr 2009

    Posted 30 Jul 2014 Link to this post

    Hi,
    I've recently updated our main project to Q2 2014 (haven't got the chance to try SP1, but according to the changes list, I don't think it will fix the problem), and went through a full battery of tests, unfortunately this uncovered that the new version broke our drag and drop implementation.
    We use CSLA objects to handle the persistence side, making the whole thing much too complicated to enable me posting some sample code (it will take days of work to cook it up), but I'll try to provide as much details as possible.

    First of all, we were happily using the old events (not the DragDropManager events) to manage everything and it worked perfectly so far.
    First issue was that Q2 2014 made the TreeViewDragDropExecutionMode default to "New" with the effect that the TreeView.PreviewDragEnded event didn't fire and our code to commit the data to the DB stopped being executed.
    I could see on intellisense that the mode is now deprecated, and that I should use the DragDropManager events instead. And here the real trouble begun.
    1. The documentation on the official help files is clearly outdated, it doesn't mention the deprecation and doesn't really make it clear how DragDropManager should be implemented (what's wrong with showing a full example?). Anyway, the demos do use it so I could get it to work.
    2. Unfortunately, the treeview is currently populated via binding and this apparently has some mysterious consequence on the built-in CSLA properties of the data object.

    What I've found is that I can get access to the dragged object via
    subscribing to DragDropManager.AddDragDropCompletedHandler(TreeView, TreeView_PreviewDragEnded, true) so to implement the data persistence into TreeView_PreviewDragEnded.
    In this method I do the following to get access to the dragged data object:

    TreeViewDragDropOptions options = DragDropPayloadManager.GetDataFromObject(e.Data, TreeViewDragDropOptions.Key) as TreeViewDragDropOptions;
    AttributeSet draggedAttribute;
                using(IEnumerator<object> iter = options.DraggedItems.GetEnumerator())
                {
                    iter.MoveNext();
                    rs = iter.Current as ReviewSet;
                    draggedAttribute = iter.Current as AttributeSet;
                }
    Note that iter.Current could be two different types of object, ReviewSet if it's a root item, AttributeSet otherwise. Both types are CSLA types of object, and have a series of fields that control their data persistence behaviour. The culprit here is the "IsDeleted" field: in both cases, the dragged object I fetch in this way has that field set to True, while all other objects have the expected "False" value.
    Now, when dragging and dropping, the "Order" field that each object uses to control its position among its siblings (and they can have quite a few) will need to be updated for plenty of items in the treeview, so to maintain consistency; in order to do so, we could proceed in two ways:
    Option one is the default CSLA version, where we would update the "order" value on all affected objects, and use the automatic behaviour to let the objects save their changes automatically. However, this is costly as each affected object will need to make its own round trip to the server to update itself, this sends back a new object that needs to be substituted in the client.
    Option two, which we chose, is: change the appropriate values on the client objects, explicitly preventing them to auto-update. Send one command to the server, with the needed information to save the changes on server side (effectively repeating the same operations on SQL). We then listen for the command result, and if no error is returned we'll know that everything is fine. So far it worked, but now, since the "IsDeleted" field mysteriously decided to get the "True" value, the dragged object invariably goes back to the server and auto deletes itself. Not nice!
    I can prevent this by telling the object to avoid the automatic update, but this won't reset the "IsDeleted" flag (as it's automatically handled by CSLA and it can't be changed) so my client list will contain objects that believe they are deleted, with unpredictable results that I don't want to discover the hard way.

    Final diagnosis: this situation won't work. Even if the DragDropManager "official" way to handle events can work, the "IsDeleted" issue seems to be a game stopper. The questions therefore are:
    - Do you have any idea of why this happens?
    - Can we "unbind" the IsDeleted property so that when we drag an object it doesn't magically decide that it's deleted?

    Temporary workaround: although deprecated, I've found that I can use the following
    private void RadTreeView_Loaded(object sender, RoutedEventArgs e)
            {
                Telerik.Windows.Controls.RadTreeView o2 = sender as Telerik.Windows.Controls.RadTreeView;
                o2.PreviewDragEnded -= RadTreeView_PreviewDragEnded;
                o2.PreviewDragEnded += new RadTreeViewDragEndedEventHandler(RadTreeView_PreviewDragEnded);
                TreeViewSettings.SetDragDropExecutionMode(o2, TreeViewDragDropExecutionMode.Legacy);
            }
    I.e., I'm still forcing the old system to work, which allows me to use the old routines and everything appears to work exactly as before (the dragged object does not get deleted!). However, this is playing with fire: someday, probably soon, you guys will decide to kill the old route and we'll find ourselves is real trouble.
    In other words, I need some answers to the questions above.
    In general, this is the second time that we get caught by scarcely or not at all documented breaking changes (the first one was about RadWindows), I write code myself, so I do understand the need to break some old things in order to move on, but I was expecting Telerik to be able to provide plenty of guidance on how to rewire stuff appropriately; in this case, I've found that your documentation is both lacking and misleading. This is the reason why I'm not using a support ticket: I'm guessing that this thread may be useful to other developers caught by the same kind of trouble.
    Sorry if I sound harsh (I usually can only say good things about Telerik!).
    Thanks and best wishes,
    Sergio

     

  2. Pavel R. Pavlov
    Admin
    Pavel R. Pavlov avatar
    1183 posts

    Posted 04 Aug 2014 Link to this post

    Hi Sergio,

    I would like to start my answer in a bit unordered way. I would like first to tell you that you are absolutely right for the referenced article. What I can do for you at this point is to ensure you that I will address this issue as soon as possible and an update of the documentation will be available in the shortest possible period. Regarding a full example demonstrating implementation of the new DragDropManager, please refer to our HowTo section of our documentation.

    Now let me try to explain why we decided to change the default settings of the RadTreeView control. As you know the RadDragAndDropManager is obsolete due to its known limitations. This is why we designed and developed the new and improved DragDropManager. Creating the newer manager allowed all our controls in the suite to use the improved code for the drag and drop operations. So we started migrating the internal logic to use the DragDropManager. Till now only the RadTreeView control still supports both managers and this prevents us from deleting the obsolete code. This is why we were forced to change the default settings of the RadTreeView. Now customers using customized drag and drop operations will be surely notified for our future plans for the obsolete control. We want to ensure that all our customers migrate their applications to use the new manager in order to delete the old one without big breaking changes. Please note that the experience that we so far have clearly shows that the time and efforts spent in migrating your application to the newer manager are well payed off in long terms. Also, our customers are happy with the new drag and drop logic.

    Now let me try to explain what we can offer you. We encourage you to migrate to the new DragDropManager as we will discontinue shipping the obsolete code at some point. Also, we will gladly answer any questions regarding any migration issues that you may encounter.

    After carefully reading the provided information about your scenario I think that I understand the big picture of your application. As far as I understand, you use CSLA object which is exposing a boolean IsDeleted flag. If this flag is set to true for any business item, it is deleted from your database. Your issue is that somehow this flag is automatically set to true after the migration. 

    Basically, when we changed the default setting of the RadTreeView control we expected that customers will complain about custom code that is not being triggered. Your issue may be caused just by that. If you have implemented custom drag drop logic in any handler of the old manager's events, this logic will not be triggered now. If any of your custom logic for handling the CSLA object is not triggered the IsDeleted flag may be automatically set. Please keep in mind that we do not provide support for CSLA objects out of the box. This is why it is up to you to properly handle those objects.

    However, the good news is that if your application was properly working with the obsolete code we will be able to make it work with the new manager. Let me first ask you to provide me with a list of the drag and drop events that are used in your application and maybe some words about the actions you take in those handlers. This will help me better understand your custom implementation.

    Regards,
    Pavel R. Pavlov
    Telerik
     
    Check out Telerik Analytics, the service which allows developers to discover app usage patterns, analyze user data, log exceptions, solve problems and profile application performance at run time. Watch the videos and start improving your app based on facts, not hunches.
     
  3. DevCraft banner
  4. Sergio Graziosi
    Sergio Graziosi avatar
    4 posts
    Member since:
    Apr 2009

    Posted 06 Aug 2014 in reply to Pavel R. Pavlov Link to this post

    Hi Pavel,
    sorry for the late reply, I was too busy on other fronts. I'll follow your unordered thread in my answer.

    Thanks for the link to the HowTo section, somehow I've missed it the first time round.
    On why moving to the new DragDropManager, I don't really know what the previous limitation were, but I don't need long explanations on this, of course you had good reasons, I'm sure of it and I'm not being sarcastic.

    After carefully reading the provided information about your scenario I think that I understand the big picture of your application. As far as I understand, you use CSLA object which is exposing a boolean IsDeleted flag. If this flag is set to true for any business item, it is deleted from your database. Your issue is that somehow this flag is automatically set to true after the migration.

    this is all 100% correct! The following bit confuses me though:

    Basically, when we changed the default setting of the RadTreeView control we expected that customers will complain about custom code that is not being triggered. Your issue may be caused just by that. If you have implemented custom drag drop logic in any handler of the old manager's events, this logic will not be triggered now. If any of your custom logic for handling the CSLA object is not triggered the IsDeleted flag may be automatically set. Please keep in mind that we do not provide support for CSLA objects out of the box. This is why it is up to you to properly handle those objects.

    You may be onto something here, but if you are you've lost me. What I was trying to explain above looks in conflict to what you are telling me now.
    The story goes like this:
    1) I update our project so to use Q2 2014
    2) we notice that drag and drop within a treeview was looking OK on the client, but changes were not saved. In another context, drag and drop from the tree into another control (also a treeview) was not working, and actually deleting the dragged elements on server side (Bad!).
    3) From there, finding out that our "custom code" was not being called was easy.
    4) First attempt to resolve the issue was by following the suggested route. Ditch the old way of handling drag/drop events and use the new way. I was able to do so (and I've kept the code), our custom code was now executed, and the only changes that seemed to be necessary had to do with how to access the relevant objects (dragged object, target object and so forth). All looked fine for a very short time.
    5) It all became worrying again when I noticed that more often that not, the (dragged) object had the "isDeleted" flag set to true. This is automatically handled by CSLA, and is read only, I can't simply check if the value is right and change it when necessary. The result is that we can drag and drop, send the relative commands to the server to send the changes, and it all works. But while all this happens the CSLA framework also sends the "deleted" object back (it all works asynchronously) and eventually the dragged object gets deleted.
    Hence my original question: do you have any idea of why dragging what is a silverlight control may impact the particular "IsDeleted" CSLA field in the underlying data-object. I am guessing some binding trickery is at play, and since this is the direct consequence of Telerik changes, I'm asking my question here (guessing that the CSLA folk will not be able to help).

    What your answer may suggest is that the flag gets changed because we are not subscribing to some event, which is then handled in the telerik default way, and that something that happens there may be interpreted by CSLA as a good reason to believe the data object should be deleted. This is not impossible, but I'm stretching your words, so I may be completely off the mark.

    As per your specific question, I can tell you that the code I've wrote for my point 4) above was handling one and one only event, I've tried a few alternatives, but with no luck. The code I've posted names the RadTreeViewDragEndedEventHandler but I'm happy to use another event, if that will solve the issue and allow us to react properly.
    What we need to achieve is allow users to drag and drop tree-branches as they may see fit. As the tree structures we handle can be quite big, this is very useful for our users. At the business logic level, this requires to change the following:
    on the "moving" node, change the value of "parentID" (identifies what data-object contains the current one) and change the "order" field, so to know where in the list of same-level objects (siblings) it should be.
    on the old siblings of the object, decrease the "order" value of the ones that came after the moved object, so to fill the missing place and leave no gaps.
    on the new siblings, increase the "order" values of the ones that now come after the moved object.
    On the old parent object, remove the moved object from the list of its children. On the receiving object, add the moved object to the list.

    What happens in the handler can be summarised in this way: 1st, the "Order" field of the data-objects associated with the affected nodes in the tree gets an update on client side (instructing CSLA that changes should not be propagated); the ParentID field of the dragged object is updated locally. All the other changes I mention above happen in the same way (they don't get individually saved to the server).
    2nd, a CSLA command is sent back to the server, containing the required information (what data object was moved, where it was, where it is now) so that exactly the same changes can be independently saved on server side. This seemed like a good idea to avoid triggering a lot of chit-chat between client and server, as otherwise all affected object would do a round trip to the server on their own.
    3rd, the command sends back to client a "success" or "error" message, the client is listening and will show an error if the commit operation failed, otherwise we'll know our data was saved successfully.

    All of the above works perfectly with the old event-handling system, handling the TreeView.PreviewDragEnded event alone. As far as I can tell, we don't subscribe to other events. Also: if my analysis is right, the only problem with the new system is the "isDeleted" flag, if it wasn't for that, it would be working just as well.
    I hope this clarifies, thanks so much for your assistance!
    Sergio
  5. Pavel R. Pavlov
    Admin
    Pavel R. Pavlov avatar
    1183 posts

    Posted 07 Aug 2014 Link to this post

    Hi Sergio,

    Thank you for providing us with more information about your scenario. However, the provided so far information is not enough for us to make any investigation of the issue that you report. The only thing that we know is that you use specific objects that are automatically deleted from your database after the migration.

    In order to assist you in this case we will ask you to provide us with project that reproduces this issue and exact steps to reproduce it on our side and binaries so we will not have to download anything. Only then we will be able to attach our source code in the project and see what causes the reported behavior. If it is caused by our code we might be able to fix it, provide you with workaround or at least share with you why this is happening after the migration.

    At this point I ensure you that if you provide us with a project reproducing this issue we will rise the priority of your issue as much as possible. If needed we will decompile the binaries of the framework that you use to see why and where the IsDeleted flag is set. This will help us to better understand the reasons behind the reported behavior.

    Thank you for your kind cooperation.

    Regards,
    Pavel R. Pavlov
    Telerik
     
    Check out Telerik Analytics, the service which allows developers to discover app usage patterns, analyze user data, log exceptions, solve problems and profile application performance at run time. Watch the videos and start improving your app based on facts, not hunches.
     
Back to Top