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.