MVVM + TreeListView + Drag&Drop

2 posts, 0 answers
  1. Miroslav
    Miroslav avatar
    4 posts
    Member since:
    Mar 2011

    Posted 04 Apr 2011 Link to this post

    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.

  2. Tsvyatko
    Admin
    Tsvyatko avatar
    832 posts

    Posted 06 Apr 2011 Link to this post

    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
  3. DevCraft banner
Back to Top