This is a migrated thread and some comments may be shown as answers.

MVVM + TreeListView + Drag&Drop

1 Answer 119 Views
TreeListView
This is a migrated thread and some comments may be shown as answers.
Miroslav
Top achievements
Rank 1
Miroslav asked on 04 Apr 2011, 08:51 AM

Hello,

Please, I need help with a scenario below.

Due to strict approach of MVVM architecture, we are forbidden to use any events from the view.

Reaching goal: Apply drag&drop on a self-referencing hierarchy list to change its parents on MVVM architecture using PRISM, MeF, Silverlight 4 and Telerik RadControls.


View layout:


<telerik:RadTreeListView ItemsSource="{Binding Items}" AutoGenerateColumns="False" IsDragDropEnabled="True" >
    <i:Interaction.Behaviors>
        <man:DragDropBehavior />
    </i:Interaction.Behaviors>
  
    <telerik:RadTreeListView.ChildTableDefinitions>
        <telerik:TreeListViewTableDefinition ItemsSource="{Binding Items}" />
    </telerik:RadTreeListView.ChildTableDefinitions>
  
    <telerik:RadTreeListView.Columns>
        <telerik:GridViewDataColumn DataMemberBinding="{Binding Unit.Name}" Header="Name" />
        <telerik:GridViewDataColumn DataMemberBinding="{Binding ItemsCount}" Header="ItemsCount" />
    </telerik:RadTreeListView.Columns>
  
</telerik:RadTreeListView>

I’ve created an encapsulation of class Unit to HierarchyUnit, to create needed source for radtreelistview. The original list is a list from database where units are referenced by parent unit ID.

/// <summary>Unit workaround for hierarchy approach.</summary>
/// <remarks>Author: MiroslavH @ 30.3.2011 15:39</remarks>
public class HierarchyUnit
{
   /// <summary>
   /// Initializes a new instance of the <see cref="HierarchyUnit"/> class.
   /// </summary>
   /// <param name="unit">The unit parameter.</param>
   /// <param name="wholeCollection">The whole collection of object.</param>
   /// <remarks>Author: MiroslavH @ 30.3.2011 15:39</remarks>
   public HierarchyUnit(Unit unit, IEnumerable<Unit> wholeCollection)
   {
      this.Unit = unit;
      this.Items = new ObservableCollection<HierarchyUnit>(wholeCollection.Where<Unit>(child => child.IdUnitMain == this.Unit.Id && child.Id != child.IdUnitMain).Select<Unit, HierarchyUnit>(u => new HierarchyUnit(u, wholeCollection)));
      this.ItemsCount = Items.Count();
   }
 
   /// <summary>Gets or sets the unit.</summary>
   /// <value>The unit value.</value>
   /// <remarks>Author: MiroslavH @ 30.3.2011 15:39</remarks>
   public Unit Unit { get; set; }
 
   /// <summary>Gets or sets the children.</summary>
   /// <value>The children.</value>
   /// <remarks>Author: MiroslavH @ 30.3.2011 15:39</remarks>
   public ObservableCollection<HierarchyUnit> Items { get; set; }
 
   /// <summary>Gets or sets the items count.</summary>
   /// <remarks>Author: MiroslavH @ 31.3.2011 14:47</remarks>
   /// <value>Items count.</value>
   public int ItemsCount { get; set; }
}


Now I’m trying to apply drag&drop scenario, but I failed with using PRISM in behaviors (everything seems to work, even in debug mode the field holding IEventAggregator instance is filled up with prism import), the event doesn’t reach the ViewModel.

Here comes the drop function in DragDropBehavior.cs:

/// <summary>Handles the OnDropInfo event of the treeList control.</summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="Telerik.Windows.Controls.DragDrop.DragDropEventArgs"/> instance containing the event data.</param>
/// <remarks>Author: MiroslavH @ 1.4.2011 9:20</remarks>
private void TreeListOnDropInfo(object sender, DragDropEventArgs e)
{
   if (e.Options.Status == DragStatus.DropComplete)
   {
      Collection<object> payload = e.Options.Payload as Collection<object>;
      HierarchyUnit droppedItem = payload[0] as HierarchyUnit;
      GridViewRow destinationRow = e.Options.Destination as GridViewRow;
 
      if (destinationRow != null)
      {
         HierarchyUnit targetItem = destinationRow.DataContext as HierarchyUnit;
         TreeListViewDropPosition relativeDropPosition = (TreeListViewDropPosition)destinationRow.GetValue(RadTreeListView.DropPositionProperty);
         _EventCall = EventAggregator.GetEvent<MaintenanceUnitChangeParent>();
         _EventCall.Publish(new Tuple<HierarchyUnit, HierarchyUnit, TreeListViewDropPosition>(droppedItem, targetItem, relativeDropPosition));
      }
   }
}

Mocked up collection:

_UnitList = new List<Unit>();
 
_UnitList.Add(new Unit() { Id = 1, Name = "Parent 1", IdUnitMain = 0 });
_UnitList.Add(new Unit() { Id = 2, Name = "Parent 2", IdUnitMain = 0 });
_UnitList.Add(new Unit() { Id = 3, Name = "Parent 3", IdUnitMain = 0 });
_UnitList.Add(new Unit() { Id = 4, Name = "Parent 4", IdUnitMain = 0 });
_UnitList.Add(new Unit() { Id = 5, Name = "Child 1 of 1", IdUnitMain = 1 });
_UnitList.Add(new Unit() { Id = 6, Name = "Child 2 of 1", IdUnitMain = 1 });
_UnitList.Add(new Unit() { Id = 7, Name = "Child 3 of 1", IdUnitMain = 1 });


Loading method:

/// <summary>Reloads the collection.</summary>
/// <remarks>Author: MiroslavH @ 1.4.2011 12:56</remarks>
private void ReloadCollection()
{
   IList<HierarchyUnit> hierarchiedList = new List<HierarchyUnit>();
 
   foreach (Unit unit in _UnitList.Where<Unit>(unit => unit.IdUnitMain == 0))
   {
      HierarchyUnit hierarchyUnit = new HierarchyUnit(unit, _UnitList);
      hierarchiedList.Add(hierarchyUnit);
   }
 
   Items = new ObservableCollection<HierarchyUnit>(hierarchiedList);
}


And finally – parent changing function, that should be called from the behavior.

/// <summary>Moves the item.</summary>
/// <param name="parameters">The parameters.</param>
/// <remarks>Author: MiroslavH @ 1.4.2011 9:20</remarks>
public void ChangeParent(Tuple<HierarchyUnit, HierarchyUnit, TreeListViewDropPosition> parameters)
{
   HierarchyUnit droppedItem = parameters.Item1;
   HierarchyUnit targetItem = parameters.Item2;
   TreeListViewDropPosition relativeDropPosition = parameters.Item3;
 
   if (droppedItem == targetItem)
   {
      // Could not set the item to have a relation with itself.
      return;
   }
 
   if (relativeDropPosition == TreeListViewDropPosition.Inside)
   {
      // Set the item as a child to original element
      Unit workUnit = _UnitList.FirstOrDefault(unit => unit.Id == droppedItem.Unit.Id);
      workUnit.IdUnitMain = targetItem.Unit.Id;
   }
   else if (relativeDropPosition == TreeListViewDropPosition.Before || relativeDropPosition == TreeListViewDropPosition.After)
   {
      // Set the item as a brother to original element
      Unit workUnit = _UnitList.FirstOrDefault(unit => unit.Id == droppedItem.Unit.Id);
      workUnit.IdUnitMain = targetItem.Unit.IdUnitMain;
   }
 
   ReloadCollection();
}


Should I use a different approach, I got a mistake anywhere or it’s not possible to do it with the rules we have?

Thank you.

1 Answer, 1 is accepted

Sort by
0
Tsvyatko
Telerik team
answered on 06 Apr 2011, 11:35 AM
Hello Miroslav,

 Would it be possible to send us small sample that exposes the issue you are facing (you can attach zip archive by opening support ticket).

Kind regards,
Tsvyatko
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
Tags
TreeListView
Asked by
Miroslav
Top achievements
Rank 1
Answers by
Tsvyatko
Telerik team
Share this question
or