Editable root lists in a tree structure (silverlight)

Editable root lists in a tree structure (silverlight)

Old forum URL: forums.lhotka.net/forums/t/6742.aspx


James Thomas posted on Sunday, April 05, 2009

Hi,

I have a tree structure (saved as a self-joined table in the database) in which my object contains a dynamic editable root list of other objects of the same type. Each of these objects can, of course, contain editable root lists of the same type, etc... This gives me a nice tree structure that can all be loaded in one go, passed to the client and databound in a treeview (as the objects themselves, not using dataproviders).

Adding, deleting and editing text in the nodes works fine, but I'm having difficulty in implementing drag and drop efficiently.

When a node is dragged and dropped, it needs removing from its original list and inserting into another. How do I go about doing this though? If it simply involved one node then I guess it would be easy enough to delete from one list (this works fine) and create a new object in another list (works fine). However, the node I'm dragging might have a complex structure of nodes below it which also need to move, ideally without reloading them all. In my days of programming in c, I'd have just changed the pointers in the lists and the job would be done. In CSLA though, when I remove an object from a list, it's marked as 'deleted' and isn't much good for then inserting into another list.

I'm sure there's a way of doing this, I just don't know CSLA well enough I guess.

Any pointers ;-) would be much appreciated.

Thanks, James.

rsbaker0 replied on Sunday, April 05, 2009

The common response I see to questions like this is that EditableRootListBase (ERLB) was designed for a very specific use case -- editing root objects in a grid -- and that it was not intended for ______. (fill in whatever poster was trying to do here).

That being said, I too find it useful for related purposes.

In this case, maybe even though the list marked the object as "deleted" -- and in fact may have even really tried to delete the object from the database, you might be able to intercept the delete call to prevent the database deletion. If an object has been marked as deleted, you can also "undelete" it. You would probably have to do this in derived classes since this would involve protected properties or overriding virtual methods.

RockfordLhotka replied on Sunday, April 05, 2009

I think he's asking about BLB lists, not ERLB lists.

It is often the case that a tree is best represented as a set of read-only objects, not editable objects. In other words, ROLB instead of BLB.

You can then have a set of Command objects that are used to perform operations on the read-only objects. The Command object can change the server-side data (in the database) and if that succeeds it can alter the client-side object graph (or at least coordinate the updates to the object graph - I'm not advocating breaking encapsulation).

As a brief example, suppose I have ListA and ListB. The UI allows the user to move items from one list to the other, and these changes are immediate (no 'Save' button - the move is auto-committed to the database). If you implement both lists as ROLB, their implementation is pretty easy, as is the UI.

When the user drops an item from B into A, the UI can invoke an AddFrom() command:

_listA.AddFrom(_listB, item);

or something like that. This AddFrom() method would invoke a Command object to do the actual work:

public void AddFrom(ListType list, ItemType item)
{
  ItemMover.DoMove(this, list, item);
}

the Command object is ItemMover, and would look like this pseudocode:

[Serializable]
internal class ItemMover : CommandBase
{
  // declare id key value properties here

  public static void DoMove(
    ListType fromList, ListType toList, ItemType item)
  {
    var cmd = new ItemMover {
      FromListId = fromList.Id,
      ToListId = toList.Id,
      ItemId = item.Id };
    DataPortal.Execute<ItemMover>(cmd);

    // we get here because the server update worked
    fromList.RemoveMovedItem(item);
    toList.AddMovedItem(item);
  }

  protected override void DataPortal_Execute()
  {
    // update database to reflect change by using
    // the id key value properties

    // throw exception if this can't be done
  }
}

Note that this does require that you implement internal RemoveMovedItem() and AddMovedItem() methods on your read-only list class. These would look like this:   

internal void RemoveMovedItem(ItemType item)
{
  IsReadOnly = false;
  try
  {
    this.Remove(item);
  }
  finally
  {
    IsReadOnly = true;
  }
}

This technique means you don't break encapsulation on any object. It provides a model by which you can implement discrete methods on what would otherwise be read-only lists, and is often the best model for implementing things list selection lists, treeviews and so forth.

James Thomas replied on Friday, April 10, 2009

Thanks! Just what I needed to get on the right track.
Thanks for your help, James.

Copyright (c) Marimer LLC