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.